├── README.md ├── kcptun.json ├── systemd.service ├── redhat.init ├── ubuntu.init ├── kcptun.sh ├── LICENSE └── kcptun_bak.sh /README.md: -------------------------------------------------------------------------------- 1 | # kcptun_installer 2 | 3 | 此仓库已废弃,请移步新仓库 [https://github.com/kuoruan/shell-scripts](https://github.com/kuoruan/shell-scripts) 4 | -------------------------------------------------------------------------------- /kcptun.json: -------------------------------------------------------------------------------- 1 | { 2 | "shell_version": 17, 3 | "shell_url": "https://github.com/kuoruan/shell-scripts/raw/master/kcptun/kcptun.sh", 4 | "change_log": "1.重写脚本,优化逻辑;\n2.将脚本移动到新的 Github 仓库;\n3.支持大部分 Linux 发行版本;\n4.支持 systemd 方式启动", 5 | "config_version": 6, 6 | "config_change_log": "1.支持 snmp 和 pprof 参数;\n2.输出新版手机端参数", 7 | "init_version": 3, 8 | "init_change_log": "1.修复 CentOS 上找不到 Supervisor 执行文件的问题;\n2.由于 Supervisor 的版本不同, 执行文件的目录可能不一样, 如果你出现无法安装或启动失败的问题, 请及时联系我" 9 | } 10 | -------------------------------------------------------------------------------- /systemd.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Supervisor process control system for UNIX 3 | Documentation=http://supervisord.org 4 | After=network.target 5 | 6 | [Service] 7 | Type=forking 8 | ExecStart=/usr/local/bin/supervisord -c /etc/supervisor/supervisord.conf 9 | ExecStop=/usr/local/bin/supervisorctl $OPTIONS shutdown 10 | ExecReload=/usr/local/bin/supervisorctl $OPTIONS reload 11 | KillMode=process 12 | Restart=on-failure 13 | RestartSec=30s 14 | 15 | [Install] 16 | WantedBy=multi-user.target 17 | -------------------------------------------------------------------------------- /redhat.init: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # 3 | # chkconfig: 345 83 04 4 | # description: Supervisor is a client/server system that allows \ 5 | # its users to monitor and control a number of processes on \ 6 | # UNIX-like operating systems. 7 | # processname: supervisord 8 | # config: /etc/supervisor/supervisord.conf 9 | # pidfile: /var/run/supervisord.pid 10 | # 11 | ### BEGIN INIT INFO 12 | # Provides: supervisord 13 | # Required-Start: $all 14 | # Required-Stop: $all 15 | # Short-Description: start and stop Supervisor process control system 16 | # Description: Supervisor is a client/server system that allows 17 | # its users to monitor and control a number of processes on 18 | # UNIX-like operating systems. 19 | ### END INIT INFO 20 | 21 | # Source function library 22 | . /etc/rc.d/init.d/functions 23 | 24 | PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin 25 | 26 | PREFIX=/usr 27 | SUPERVISORD=$PREFIX/bin/supervisord 28 | SUPERVISORCTL=$PREFIX/bin/supervisorctl 29 | NAME=supervisord 30 | PIDFILE=/var/run/supervisord.pid 31 | OPTIONS="-c /etc/supervisor/supervisord.conf" 32 | STOP_TIMEOUT=10 33 | RETVAL=0 34 | 35 | test -x $SUPERVISORD || exit 1 36 | 37 | do_start() { 38 | if status -p $PIDFILE $SUPERVISORD >&/dev/null; then 39 | echo "$NAME is already running." 40 | RETVAL=0 41 | else 42 | echo -n $"Starting $NAME: " 43 | daemon --pidfile=$PIDFILE $SUPERVISORD $OPTIONS -j $PIDFILE 44 | RETVAL=$? 45 | echo 46 | [ $RETVAL -eq 0 ] && $SUPERVISORCTL $OPTIONS status 47 | fi 48 | 49 | } 50 | 51 | do_stop() { 52 | if status -p $PIDFILE $SUPERVISORD >&/dev/null; then 53 | echo -n $"Stopping $NAME: " 54 | killproc -p $PIDFILE -d $STOP_TIMEOUT $SUPERVISORD 55 | RETVAL=$? 56 | echo 57 | [ $RETVAL -eq 0 ] && rm -rf $PIDFILE 58 | else 59 | echo "$NAME is not running." 60 | RETVAL=0 61 | fi 62 | } 63 | 64 | chk_status() { 65 | status -p $PIDFILE $SUPERVISORD 66 | RETVAL=$? 67 | [ $RETVAL -eq 0 ] && $SUPERVISORCTL $OPTIONS status 68 | } 69 | 70 | case "$1" in 71 | start) 72 | do_start 73 | ;; 74 | stop) 75 | do_stop 76 | ;; 77 | status) 78 | chk_status 79 | ;; 80 | restart) 81 | do_stop 82 | do_start 83 | ;; 84 | *) 85 | echo $"Usage: /etc/init.d/$NAME {start|stop|restart|status}" 86 | RETVAL=2 87 | ;; 88 | esac 89 | 90 | exit $RETVAL 91 | -------------------------------------------------------------------------------- /ubuntu.init: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # 3 | ### BEGIN INIT INFO 4 | # Provides: supervisor 5 | # Required-Start: $remote_fs $network $named 6 | # Required-Stop: $remote_fs $network $named 7 | # Default-Start: 2 3 4 5 8 | # Default-Stop: 0 1 6 9 | # Short-Description: Start/stop supervisor 10 | # Description: Start/stop supervisor daemon and its configured 11 | # subprocesses. 12 | ### END INIT INFO 13 | 14 | . /lib/lsb/init-functions 15 | 16 | PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin 17 | 18 | PREFIX=/usr/local 19 | SUPERVISORD=$PREFIX/bin/supervisord 20 | SUPERVISORCTL=$PREFIX/bin/supervisorctl 21 | NAME=supervisord 22 | PIDFILE=/var/run/supervisord.pid 23 | OPTIONS="-c /etc/supervisor/supervisord.conf" 24 | STOP_TIMEOUT=10 25 | RETVAL=0 26 | 27 | SCRIPT_OK=0 28 | SCRIPT_ERROR=1 29 | 30 | test -x $SUPERVISORD || exit 1 31 | 32 | is_running() { 33 | # Check if the process is running looking at /proc 34 | # (works for all users) 35 | 36 | # No pidfile, probably no daemon present 37 | [ ! -f "$PIDFILE" ] && return 1 38 | # Obtain the pid and check it against the binary name 39 | pid=`cat $PIDFILE` 40 | (ps aux | grep -v grep | grep $SUPERVISORD | grep -q $pid) || return 1 41 | return 0 42 | } 43 | 44 | do_start() { 45 | log_daemon_msg "Starting $NAME: " 46 | 47 | if is_running; then 48 | log_end_msg $SCRIPT_ERROR 49 | echo "$NAME is already running." 50 | RETVAL=0 51 | else 52 | start-stop-daemon --start --quiet --pidfile $PIDFILE \ 53 | --startas $SUPERVISORD -- $OPTIONS -j $PIDFILE 54 | [ -f $PIDFILE ] || sleep 1 55 | if is_running; then 56 | log_end_msg $SCRIPT_OK 57 | $SUPERVISORCTL $OPTIONS status 58 | RETVAL=0 59 | else 60 | log_end_msg $SCRIPT_ERROR 61 | RETVAL=1 62 | fi 63 | fi 64 | } 65 | 66 | do_stop() { 67 | log_daemon_msg "Stopping $NAME: " 68 | if is_running; then 69 | start-stop-daemon --stop --retry TERM/$STOP_TIMEOUT/KILL/5 --quiet --oknodo --pidfile $PIDFILE 70 | log_end_msg $SCRIPT_OK 71 | RETVAL=0 72 | else 73 | log_end_msg $SCRIPT_ERROR 74 | echo "$NAME is not running." 75 | RETVAL=0 76 | fi 77 | } 78 | 79 | chk_status() { 80 | echo -n "$NAME is " 81 | if is_running; then 82 | echo "running." 83 | $SUPERVISORCTL $OPTIONS status 84 | RETVAL=0 85 | else 86 | echo "not running." 87 | RETVAL=0 88 | fi 89 | } 90 | 91 | case "$1" in 92 | start) 93 | do_start 94 | ;; 95 | stop) 96 | do_stop 97 | ;; 98 | restart) 99 | do_stop 100 | do_start 101 | ;; 102 | status) 103 | chk_status 104 | ;; 105 | *) 106 | echo "Usage: /etc/init.d/$NAME {start|stop|restart|status}" 107 | RETVAL=2 108 | ;; 109 | esac 110 | 111 | exit $RETVAL 112 | -------------------------------------------------------------------------------- /kcptun.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | : <<-'EOF' 4 | Copyright 2016 Xingwang Liao 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | EOF 18 | 19 | export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin 20 | 21 | OLD_SHELL_URL='https://github.com/kuoruan/kcptun_installer/raw/master/kcptun_bak.sh' 22 | NEW_SHELL_URL='https://github.com/kuoruan/shell-scripts/raw/master/kcptun/kcptun.sh' 23 | NEW_REPO_URL='https://github.com/kuoruan/shell-scripts' 24 | 25 | clear 26 | 27 | cat >&2 <<-'EOF' 28 | ######################################################### 29 | # Kcptun 服务端一键安装脚本 # 30 | # 该脚本支持 Kcptun 服务端的安装、更新、卸载及配置 # 31 | # 脚本作者: Index # 32 | # 作者博客: https://blog.kuoruan.com/ # 33 | # Github: https://github.com/kuoruan/shell-scripts # 34 | # QQ交流群: 43391448, 68133628 # 35 | # 633945405 # 36 | ######################################################### 37 | EOF 38 | 39 | # 检查命令是否存在 40 | command_exists() { 41 | command -v "$@" >/dev/null 2>&1 42 | } 43 | 44 | # 检查当前用户是否拥有管理员权限 45 | permission_check() { 46 | if [ $EUID -ne 0 ]; then 47 | cat >&2 <<-'EOF' 48 | 49 | 权限错误, 请使用 root 用户运行此脚本! 50 | EOF 51 | exit 1 52 | fi 53 | } 54 | 55 | # 任意键继续 56 | any_key_to_continue() { 57 | SAVEDSTTY=`stty -g` 58 | stty -echo 59 | stty cbreak 60 | dd if=/dev/tty bs=1 count=1 2> /dev/null 61 | stty -raw 62 | stty echo 63 | stty $SAVEDSTTY 64 | } 65 | 66 | # 安装需要的依赖软件 67 | install_dependence() { 68 | if command_exists wget; then 69 | return 0 70 | fi 71 | 72 | if command_exists yum; then 73 | ( 74 | set -x 75 | yum install -y wget ca-certificates 76 | ) 77 | 78 | elif command_exists apt-get; then 79 | ( 80 | set -x 81 | apt-get -y update 82 | apt-get -y install wget ca-certificates 83 | ) 84 | fi 85 | 86 | set +x 87 | } 88 | 89 | do_action() { 90 | permission_check 91 | 92 | local action=${1:-'install'} 93 | local id=$2 94 | 95 | cat >&2 <<-EOF 96 | 当前脚本已发布新版本,地址: 97 | ${NEW_SHELL_URL} 98 | 99 | 旧仓库已废弃,以后所有的脚本都会发布到新仓库: 100 | ${NEW_REPO_URL} 101 | 102 | 如果你正在使用旧版,可以切换到脚本目录下运行: 103 | ./kcptun.sh update 104 | 可以直接升级到新版。 105 | 106 | 如果你想继续使用旧版本,请自行下载: 107 | ${OLD_SHELL_URL} 108 | 109 | 请按任意键自动下载运行新版脚本, 或者 Ctrl + C 退出 110 | EOF 111 | 112 | any_key_to_continue 113 | 114 | ( 115 | set -x 116 | sleep 3 117 | ) 118 | 119 | install_dependence 120 | 121 | local shell_name="$0" 122 | local back_name="${shell_name}.bak" 123 | ( 124 | set -x 125 | mv -f "$shell_name" "$back_name" 126 | ) 127 | 128 | if (wget --no-check-certificate -O "$shell_name" "$NEW_SHELL_URL"); then 129 | ( 130 | set -x 131 | rm -f "$back_name" 132 | chmod a+x "$shell_name" 133 | ) 134 | cat >&2 <<-EOF 135 | 新脚本下载完成, 136 | 三秒后开始执行新脚本... 137 | EOF 138 | 139 | ( 140 | set -x 141 | sleep 3 142 | bash "$shell_name" "$action" "$id" 143 | ) 144 | else 145 | ( 146 | set -x 147 | mv -f "$back_name" "$shell_name" 148 | ) 149 | 150 | cat >&2 <<-EOF 151 | 文件自动下载失败, 152 | 请手动下载运行新脚本: 153 | ${NEW_SHELL_URL} 154 | EOF 155 | 156 | exit 1 157 | fi 158 | } 159 | 160 | do_action "$1" "$2" 161 | 162 | exit 0 163 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /kcptun_bak.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | : <<-'EOF' 4 | Copyright 2016 Xingwang Liao 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | EOF 18 | 19 | PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin 20 | export PATH 21 | 22 | ## 定义常量 23 | 24 | SHELL_VERSION=16 25 | CONFIG_VERSION=5 26 | INIT_VERSION=3 27 | 28 | CUR_DIR=`pwd` # 当前目录 29 | KCPTUN_INSTALL_DIR=/usr/share/kcptun # kcptun 默认安装目录 30 | KCPTUN_LOG_DIR=/var/log/kcptun # kcptun 日志目录 31 | KCPTUN_RELEASES_URL="https://api.github.com/repos/xtaci/kcptun/releases" 32 | KCPTUN_TAGS_URL="https://github.com/xtaci/kcptun/tags" 33 | SHELL_VERSION_INFO_URL="https://raw.githubusercontent.com/kuoruan/shell-scripts/master/kcptun/version.json" 34 | JQ_LINUX32="https://github.com/stedolan/jq/releases/download/jq-1.5/jq-linux32" 35 | JQ_LINUX64="https://github.com/stedolan/jq/releases/download/jq-1.5/jq-linux64" 36 | JQ=/usr/bin/jq 37 | 38 | ## 参数默认值 39 | # associative array 40 | declare -Ar DEFAULT=( 41 | [LISTEN]=29900 42 | [TARGET_IP]="127.0.0.1" 43 | [TARGET_PORT]=12948 44 | [KEY]="it's a secrect" 45 | [CRYPT]="aes" 46 | [MODE]="fast" 47 | [MTU]=1350 48 | [SNDWND]=512 49 | [RCVWND]=512 50 | [DATASHARD]=10 51 | [PARITYSHARD]=3 52 | [DSCP]=0 53 | [NOCOMP]=false 54 | [NODELAY]=0 55 | [INTERVAL]=20 56 | [RESEND]=2 57 | [NC]=1 58 | [ACKNODELAY]=false 59 | [SOCKBUF]=4194304 60 | [KEEPALIVE]=10 61 | [RUN_USER]="root" 62 | ) 63 | 64 | declare -ar CRYPTS=( 65 | "aes" 66 | "aes-128" 67 | "aes-192" 68 | "salsa20" 69 | "blowfish" 70 | "twofish" 71 | "cast5" 72 | "3des" 73 | "tea" 74 | "xtea" 75 | "xor" 76 | "none" 77 | ) 78 | 79 | declare -ar MODES=( 80 | "normal" 81 | "fast" 82 | "fast2" 83 | "fast3" 84 | "manual" 85 | ) 86 | 87 | # 初始化参数 88 | listen_port=${DEFAULT[LISTEN]} 89 | target_ip=${DEFAULT[TARGET_IP]} 90 | target_port=${DEFAULT[TARGET_PORT]} 91 | key=${DEFAULT[KEY]} 92 | crypt=${DEFAULT[CRYPT]} 93 | mode=${DEFAULT[MODE]} 94 | mtu=${DEFAULT[MTU]} 95 | sndwnd=${DEFAULT[SNDWND]} 96 | rcvwnd=${DEFAULT[RCVWND]} 97 | datashard=${DEFAULT[DATASHARD]} 98 | parityshard=${DEFAULT[PARITYSHARD]} 99 | dscp=${DEFAULT[DSCP]} 100 | nocomp=${DEFAULT[NOCOMP]} 101 | nodelay=${DEFAULT[NODELAY]} 102 | interval=${DEFAULT[INTERVAL]} 103 | resend=${DEFAULT[RESEND]} 104 | nc=${DEFAULT[NC]} 105 | acknodelay=${DEFAULT[ACKNODELAY]} 106 | sockbuf=${DEFAULT[SOCKBUF]} 107 | keepalive=${DEFAULT[KEEPALIVE]} 108 | run_user=${DEFAULT[RUN_USER]} 109 | 110 | current_id="" 111 | 112 | clear 113 | 114 | cat >&2 <<-'EOF' 115 | ######################################################### 116 | # Kcptun 服务端一键安装脚本 # 117 | # 该脚本支持 Kcptun 服务端的安装、更新、卸载及配置 # 118 | # 脚本作者: Index # 119 | # 作者博客: https://blog.kuoruan.com/ # 120 | # Github: https://github.com/kuoruan/kcptun_installer # 121 | # QQ交流群: 43391448, 68133628 # 122 | ######################################################### 123 | EOF 124 | 125 | # 检查命令是否存在 126 | command_exists() { 127 | command -v "$@" >/dev/null 2>&1 128 | } 129 | 130 | # 检查变量是否为数字 131 | is_number() { 132 | expr $1 + 1 >/dev/null 2>&1 133 | } 134 | 135 | # 获取实例数量 136 | get_instance_count() { 137 | ls -l /etc/supervisor/conf.d/ | grep "^-" | awk '{print $9}' | grep -cP "^kcptun\d*\.conf$" 138 | } 139 | 140 | # 获取当前配置文件 141 | get_current_config_file() { 142 | echo "${KCPTUN_INSTALL_DIR}/server-config${current_id}.json" 143 | } 144 | 145 | # 获取当前日志文件 146 | get_current_log_file() { 147 | echo "${KCPTUN_LOG_DIR}/server${current_id}.log" 148 | } 149 | 150 | # 获取当前实例的 Supervisor 配置文件 151 | get_current_supervisor_config_file() { 152 | echo "/etc/supervisor/conf.d/kcptun"${current_id}".conf" 153 | } 154 | 155 | # 获取当前监听端口 156 | get_current_listen_port() { 157 | local config_file="$(get_current_config_file)" 158 | 159 | if [ -f "$config_file" ]; then 160 | local listen=$($JQ -r ".listen" "$config_file") 161 | local current_listen_port=$(cut -d ':' -f2 <<< "$listen") 162 | 163 | if [ -n "$current_listen_port" ] && is_number $current_listen_port; then 164 | echo "$current_listen_port" 165 | fi 166 | fi 167 | } 168 | 169 | # 检查当前用户是否拥有管理员权限 170 | permission_check() { 171 | if [ $EUID -ne 0 ]; then 172 | cat >&2 <<-'EOF' 173 | 174 | 权限错误, 请使用 root 用户运行此脚本! 175 | EOF 176 | exit 1 177 | fi 178 | } 179 | 180 | # 检查并获取系统信息 181 | linux_check() { 182 | if $(grep -qi "CentOS" /etc/issue) || $(grep -q "CentOS" /etc/*-release); then 183 | OS="CentOS" 184 | elif $(grep -qi "Ubuntu" /etc/issue) || $(grep -q "Ubuntu" /etc/*-release); then 185 | OS="Ubuntu" 186 | elif $(grep -qi "Debian" /etc/issue) || $(grep -q "Debian" /etc/*-release); then 187 | OS="Debian" 188 | else 189 | cat >&2 <<-'EOF' 190 | 191 | 本脚本仅支持 CentOS 6+, Debian 7+ 或者 Ubuntu 12+, 其他系统请向脚本作者反馈以寻求支持! 192 | EOF 193 | exit 1 194 | fi 195 | 196 | OS_VSRSION=$(grep -oEh "[0-9]+" /etc/*-release | head -n 1) || { 197 | cat >&2 <<-'EOF' 198 | 199 | 无法获取操作系统版本, 请联系脚本作者反馈错误! 200 | EOF 201 | exit 1 202 | } 203 | 204 | if [ "$OS" = "CentOS" -a $OS_VSRSION -lt 6 ]; then 205 | cat >&2 <<-'EOF' 206 | 207 | 暂不支持 CentOS 6 以下版本, 请升级系统或向脚本作者反馈以寻求支持! 208 | EOF 209 | 210 | exit 1 211 | fi 212 | 213 | if [ "$OS" = "Ubuntu" -a $OS_VSRSION -lt 12 ]; then 214 | cat >&2 <<-'EOF' 215 | 216 | 暂不支持 Ubuntu 12 以下版本, 请升级系统或向脚本作者反馈以寻求支持! 217 | EOF 218 | exit 1 219 | fi 220 | 221 | if [ "$OS" = "Debian" -a $OS_VSRSION -lt 7 ]; then 222 | cat >&2 <<-'EOF' 223 | 224 | 暂不支持 Debian 7 以下版本, 请升级系统或向脚本作者反馈以寻求支持! 225 | EOF 226 | exit 1 227 | fi 228 | } 229 | 230 | # 获取系统位数 231 | get_arch() { 232 | if $(uname -m | grep -q "64") || $(getconf LONG_BIT | grep -q "64"); then 233 | ARCH=64 234 | SPRUCE_TYPE="linux-amd64" 235 | FILE_SUFFIX="linux_amd64" 236 | else 237 | ARCH=32 238 | SPRUCE_TYPE="linux-386" 239 | FILE_SUFFIX="linux_386" 240 | fi 241 | } 242 | 243 | # 获取服务器的IP地址 244 | get_server_ip() { 245 | SERVER_IP=$(ip addr | grep -Eo "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" | \ 246 | grep -Ev "^192\.168|^172\.1[6-9]\.|^172\.2[0-9]\.|^172\.3[0-2]\.|^10\.|^127\.|^255\.|^0\." | \ 247 | head -n 1) 248 | [ -z "$SERVER_IP" ] && SERVER_IP=$(wget -q -O - ipv4.icanhazip.com) 249 | } 250 | 251 | # 禁用 selinux 252 | disable_selinux() { 253 | if [ -s /etc/selinux/config ] && $(grep -q "SELINUX=enforcing" /etc/selinux/config); then 254 | sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config 255 | setenforce 0 256 | fi 257 | } 258 | 259 | # 非正常退出 260 | exit_with_error() { 261 | cat >&2 <<-'EOF' 262 | 263 | Kcptun 服务端安装或配置过程中出现错误! 264 | 希望你能记录下错误信息, 然后将错误信息发送给我 265 | QQ群: 43391448, 68133628 266 | 邮箱: kuoruan@gmail.com 267 | 博客: https://blog.kuoruan.com/ 268 | EOF 269 | exit 1 270 | } 271 | 272 | # 任意键继续 273 | any_key_to_continue() { 274 | SAVEDSTTY=`stty -g` 275 | stty -echo 276 | stty cbreak 277 | dd if=/dev/tty bs=1 count=1 2> /dev/null 278 | stty -raw 279 | stty echo 280 | stty $SAVEDSTTY 281 | } 282 | 283 | # 检查是否已经安装 284 | installed_check() { 285 | if [ -s /etc/supervisord.conf ]; then 286 | cat >&2 <<-EOF 287 | 288 | 检测到你曾经通过其他方式安装过 Supervisor , 这会和本脚本安装的 Supervisor 产生冲突 289 | 推荐你备份当前 Supervisor 配置后卸载原有版本 290 | 已安装的 Supervisor 配置文件路径为: /etc/supervisord.conf 291 | 通过本脚本安装的 Supervisor 配置文件路径为: /etc/supervisor/supervisord.conf 292 | 你可以使用以下命令来卸载清理原有版本: 293 | 294 | mv /etc/supervisord.conf /etc/supervisord.conf.bak 295 | $([ "${OS}" = "CentOS" ] && echo -n "yum remove supervisor" || echo -n "apt-get remove --purge supervisor") 296 | 297 | 然后, 请重新运行脚本安装 298 | EOF 299 | 300 | exit_with_error 301 | fi 302 | 303 | if [ -d /etc/supervisor/conf.d/ ]; then 304 | local instance_count=$(get_instance_count) 305 | 306 | if [ $instance_count -gt 0 ] && [ -d "$KCPTUN_INSTALL_DIR" ]; then 307 | cat >&2 <<-EOF 308 | 309 | 检测到你已安装 Kcptun 服务端, 已配置的实例个数为 ${instance_count} 个 310 | EOF 311 | while : 312 | do 313 | cat >&2 <<-'EOF' 314 | 315 | 请选择你希望的操作: 316 | (1) 覆盖安装 317 | (2) 重新配置 318 | (3) 添加实例(多用户) 319 | (4) 检查更新 320 | (5) 查看配置 321 | (6) 查看日志输出 322 | (7) 自定义版本安装 323 | (8) 删除实例 324 | (9) 完全卸载 325 | (10) 退出脚本 326 | EOF 327 | read -p "(默认: 1) 请选择 [1~10]: " sel 328 | echo 329 | [ -z "$sel" ] && sel=1 330 | 331 | case $sel in 332 | 1) 333 | echo "开始覆盖安装 Kcptun 服务端..." 334 | return 0 335 | ;; 336 | 2) 337 | select_instance 338 | reconfig_instance 339 | ;; 340 | 3) 341 | add_instance 342 | ;; 343 | 4) 344 | check_update 345 | ;; 346 | 5) 347 | select_instance 348 | show_instance_config 349 | ;; 350 | 6) 351 | select_instance 352 | show_instance_log 353 | ;; 354 | 7) 355 | manual_install 356 | ;; 357 | 8) 358 | select_instance 359 | del_instance 360 | ;; 361 | 9) 362 | uninstall_kcptun 363 | ;; 364 | 10) 365 | ;; 366 | *) 367 | echo "输入有误, 请输入有效数字 1~10!" 368 | continue 369 | ;; 370 | esac 371 | 372 | exit 0 373 | done 374 | fi 375 | fi 376 | } 377 | 378 | # 检测端口是否被占用 379 | check_port() { 380 | [ $# -lt 1 ] && return 1 381 | local port=$1 382 | 383 | if command_exists netstat; then 384 | return $(netstat -ntul | grep -qE "[0-9:]:${port}\s") 385 | elif command_exists ss; then 386 | return $(ss -ntul | grep -qE "[0-9:]:${port}\s") 387 | else 388 | return 1 389 | fi 390 | } 391 | 392 | # 设置 Kcptun 端口 393 | set_listen_port() { 394 | while : 395 | do 396 | cat >&2 <<-'EOF' 397 | 398 | 请输入 Kcptun 服务端运行端口 [1~65535] 399 | EOF 400 | read -p "(默认: ${DEFAULT[LISTEN]}): " input 401 | echo 402 | if [ -n "$input" ]; then 403 | if is_number $input && [ $input -ge 1 -a $input -le 65535 ]; then 404 | listen_port="$input" 405 | else 406 | echo "输入有误, 请输入 1~65535 之间的数字!" 407 | continue 408 | fi 409 | fi 410 | 411 | current_listen_port=$(get_current_listen_port) 412 | if check_port $listen_port && [ "$listen_port" != "$current_listen_port" ]; then 413 | echo "端口已被占用, 请重新输入!" 414 | continue 415 | fi 416 | 417 | cat >&2 <<-EOF 418 | --------------------------- 419 | 端口 = ${listen_port} 420 | --------------------------- 421 | EOF 422 | break 423 | done 424 | } 425 | 426 | # 禁用 IPv6 427 | set_disable_ipv6() { 428 | while : 429 | do 430 | cat >&2 <<-'EOF' 431 | 432 | 是否禁用 IPv6? 433 | EOF 434 | read -p "(默认: 不禁用) [y/n]: " yn 435 | echo 436 | if [ -n "$yn" ]; then 437 | case ${yn:0:1} in 438 | y|Y) 439 | listen_addr=$SERVER_IP 440 | ;; 441 | n|N) 442 | unset listen_addr 443 | ;; 444 | *) 445 | echo "输入有误, 请重新输入!" 446 | continue 447 | ;; 448 | esac 449 | fi 450 | 451 | cat >&2 <<-EOF 452 | --------------------------- 453 | $([ -z "${listen_addr}" ] && echo "不禁用IPv6" || echo "禁用IPv6") 454 | --------------------------- 455 | EOF 456 | break 457 | done 458 | } 459 | 460 | # 设置加速的ip地址 461 | set_target_ip() { 462 | while : 463 | do 464 | cat >&2 <<-'EOF' 465 | 466 | 请输入需要加速的 IP [0.0.0.0 ~ 255.255.255.255] 467 | EOF 468 | read -p "(默认: ${DEFAULT[TARGET_IP]}): " input 469 | echo 470 | if [ -n "$input" ]; then 471 | grep -qE '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$' <<< "$input" 472 | if [ $? -ne 0 ]; then 473 | echo "IP 地址格式有误, 请重新输入!" 474 | continue 475 | fi 476 | 477 | target_ip="$input" 478 | fi 479 | 480 | cat >&2 <<-EOF 481 | --------------------------- 482 | 加速 IP = ${target_ip} 483 | --------------------------- 484 | EOF 485 | break 486 | done 487 | } 488 | 489 | # 设置加速的端口 490 | set_target_port() { 491 | while : 492 | do 493 | cat >&2 <<-'EOF' 494 | 495 | 请输入需要加速的端口 [1~65535] 496 | EOF 497 | read -p "(默认: ${DEFAULT[TARGET_PORT]}): " input 498 | echo 499 | if [ -n "$input" ]; then 500 | if is_number $input && [ $input -ge 1 -a $input -le 65535 ]; then 501 | if [ $input -eq $listen_port ]; then 502 | echo "加速端口不能和 Kcptun 端口一致!" 503 | continue 504 | fi 505 | 506 | target_port=$input 507 | else 508 | echo "输入有误, 请输入 1~65535 之间的数字!" 509 | continue 510 | fi 511 | fi 512 | 513 | if [ "$target_ip" = "${DEFAULT[TARGET_IP]}" ]; then 514 | if ! check_port $target_port; then 515 | read -p "当前没有软件使用此端口, 确定加速此端口? [y/n]: " yn 516 | [ -z "$yn" ] && yn="y" 517 | case ${yn:0:1} in 518 | y|Y) 519 | ;; 520 | *) 521 | continue 522 | ;; 523 | esac 524 | fi 525 | fi 526 | 527 | cat >&2 <<-EOF 528 | --------------------------- 529 | 加速端口 = ${target_port} 530 | --------------------------- 531 | EOF 532 | break 533 | done 534 | } 535 | 536 | # 设置 Kcptun 密码 537 | set_key() { 538 | cat >&2 <<-'EOF' 539 | 540 | 请输入 Kcptun 密码 541 | EOF 542 | read -p "(默认密码: ${DEFAULT[KEY]}): " input 543 | echo 544 | [ -n "$input" ] && key="$input" 545 | 546 | cat >&2 <<-EOF 547 | --------------------------- 548 | 密码 = ${key} 549 | --------------------------- 550 | EOF 551 | } 552 | 553 | # 设置加密方式 554 | set_crypt() { 555 | while : 556 | do 557 | cat >&2 <<-'EOF' 558 | 559 | 请选择加密方式(crypt): 560 | EOF 561 | 562 | for ((i=0; i<${#CRYPTS[@]}; i++)); do 563 | echo "($(($i + 1))) ${CRYPTS[$i]}" 564 | done 565 | 566 | read -p "(默认: ${DEFAULT[CRYPT]}) 请选择 [1~$i]: " sel 567 | echo 568 | if [ -n "$sel" ]; then 569 | if is_number $sel && [ $sel -ge 1 -a $sel -le $i ]; then 570 | crypt=${CRYPTS[$(($sel - 1))]} 571 | else 572 | echo "请输入有效数字 1~$i!" 573 | continue 574 | fi 575 | fi 576 | 577 | cat >&2 <<-EOF 578 | ----------------------------- 579 | 加密方式 = ${crypt} 580 | ----------------------------- 581 | EOF 582 | break 583 | done 584 | } 585 | 586 | # 设置加速模式 587 | set_mode() { 588 | while : 589 | do 590 | cat >&2 <<-'EOF' 591 | 592 | 请选择加速模式(mode): 593 | EOF 594 | 595 | for ((i=0; i<${#MODES[@]}; i++)); do 596 | echo "($(($i + 1))) ${MODES[$i]}" 597 | done 598 | 599 | read -p "(默认: ${DEFAULT[MODE]}) 请选择 [1~$i]: " sel 600 | echo 601 | if [ -n "$sel" ]; then 602 | if is_number $sel && [ $sel -ge 1 -a $sel -le $i ]; then 603 | mode=${MODES[$(($sel - 1))]} 604 | else 605 | echo "请输入有效数字 1~$i!" 606 | continue 607 | fi 608 | fi 609 | 610 | cat >&2 <<-EOF 611 | --------------------------- 612 | 加速模式 = ${mode} 613 | --------------------------- 614 | EOF 615 | break 616 | done 617 | 618 | [ "$mode" = "manual" ] && set_manual_parameters 619 | } 620 | 621 | # 设置手动挡参数 622 | set_manual_parameters() { 623 | while : 624 | do 625 | cat >&2 <<-'EOF' 626 | 627 | 请设置手动挡参数(预设值或手动设置): 628 | (1) 策略1: 通过超时重传+快速重传, 响应速度优先 (最大化响应时间, 适用于网页访问) 629 | (2) 策略2-1: 仅仅通过超时重传, 带宽效率优先 (有效载比优先, 适用于视频观看) 630 | (3) 策略2-2: 同上, 与 策略2-1 参数略不相同 631 | (4) 策略3: 尽可能通过 FEC 纠删, 最大化传输速度 (较为中庸, 兼顾网页和视频) 632 | (5) 自定义手动挡参数 633 | EOF 634 | read -p "(默认: 5) 请选择 [1~5]: " sel 635 | echo 636 | [ -z "$sel" ] && sel=5 637 | case $sel in 638 | 1) 639 | nodelay=1 640 | interval=20 641 | resend=2 642 | nc=1 643 | ;; 644 | 2) 645 | nodelay=1 646 | interval=40 647 | resend=0 648 | nc=1 649 | ;; 650 | 3) 651 | nodelay=0 652 | interval=20 653 | resend=0 654 | nc=1 655 | ;; 656 | 4) 657 | nodelay=0 658 | interval=40 659 | resend=0 660 | nc=1 661 | datashard=5 662 | parityshard=2 663 | ;; 664 | 5) 665 | set_manual_detail_parameters 666 | break 667 | ;; 668 | *) 669 | echo "请输入有效数字 1~5!" 670 | continue 671 | ;; 672 | esac 673 | 674 | cat >&2 <<-EOF 675 | --------------------------- 676 | nodelay = ${nodelay} 677 | interval = ${interval} 678 | resend = ${resend} 679 | nc = ${nc} 680 | datashard = ${datashard} 681 | parityshard = ${parityshard} 682 | --------------------------- 683 | EOF 684 | break 685 | done 686 | } 687 | 688 | # 设置手动模式详细参数 689 | set_manual_detail_parameters() { 690 | cat >&2 <<-'EOF' 691 | 692 | 开始配置手动挡参数... 693 | EOF 694 | 695 | set_nodelay 696 | set_interval 697 | set_resend 698 | set_nc 699 | } 700 | 701 | set_nodelay() { 702 | while : 703 | do 704 | cat >&2 <<-'EOF' 705 | 706 | 是否启用 nodelay 模式? 707 | EOF 708 | read -p "(默认: 不启用) [y/n]: " yn 709 | echo 710 | if [ -n "$yn" ]; then 711 | case ${yn:0:1} in 712 | y|Y) 713 | nodelay=1 714 | ;; 715 | n|N) 716 | nodelay=0 717 | ;; 718 | * ) 719 | echo "输入有误, 请重新输入!" 720 | continue 721 | ;; 722 | esac 723 | fi 724 | 725 | cat >&2 <<-EOF 726 | --------------------------- 727 | nodelay = ${nodelay} 728 | --------------------------- 729 | EOF 730 | break 731 | done 732 | } 733 | 734 | set_interval() { 735 | while : 736 | do 737 | cat >&2 <<-'EOF' 738 | 739 | 请设置协议内部工作的 interval 740 | EOF 741 | read -p "(单位: ms, 默认: ${DEFAULT[INTERVAL]}): " input 742 | echo 743 | if [ -n "$input" ]; then 744 | if ! is_number $input || [ $input -le 0 ]; then 745 | echo "输入有误, 请输入大于0的数字!" 746 | continue 747 | fi 748 | 749 | interval=$input 750 | fi 751 | 752 | cat >&2 <<-EOF 753 | --------------------------- 754 | interval = ${interval} 755 | --------------------------- 756 | EOF 757 | break 758 | done 759 | } 760 | 761 | set_resend() { 762 | while : 763 | do 764 | cat >&2 <<-'EOF' 765 | 766 | 是否启用快速重传模式(resend)? 767 | (1) 不启用 768 | (2) 启用 769 | (3) 2次ACK跨越重传 770 | EOF 771 | read -p "(默认: 3) 请选择 [1~3]: " sel 772 | echo 773 | if [ -n "$sel" ]; then 774 | case $sel in 775 | 1) 776 | resend=0 777 | ;; 778 | 2) 779 | resend=1 780 | ;; 781 | 3) 782 | resend=2 783 | ;; 784 | *) 785 | cat >&2 <<-'EOF' 786 | 787 | 请输入有效数字 1~3! 788 | EOF 789 | continue 790 | ;; 791 | esac 792 | fi 793 | 794 | cat >&2 <<-EOF 795 | --------------------------- 796 | resend = ${resend} 797 | --------------------------- 798 | EOF 799 | break 800 | done 801 | } 802 | 803 | set_nc() { 804 | while : 805 | do 806 | cat >&2 <<-'EOF' 807 | 808 | 是否关闭流控(nc)? 809 | EOF 810 | read -p "(默认: 关闭) [y/n]: " yn 811 | echo 812 | if [ -n "$yn" ]; then 813 | case ${yn:0:1} in 814 | y|Y) 815 | nc=1 816 | ;; 817 | n|N) 818 | nc=0 819 | ;; 820 | *) 821 | echo "输入有误, 请重新输入!" 822 | continue 823 | ;; 824 | esac 825 | fi 826 | 827 | cat >&2 <<-EOF 828 | --------------------------- 829 | nc = ${nc} 830 | --------------------------- 831 | EOF 832 | break 833 | done 834 | } 835 | 836 | set_mtu() { 837 | while : 838 | do 839 | cat >&2 <<-'EOF' 840 | 841 | 请设置 UDP 数据包的 MTU (最大传输单元)值 842 | EOF 843 | read -p "(默认: ${DEFAULT[MTU]}): " input 844 | echo 845 | if [ -n "$input" ]; then 846 | if ! is_number $input || [ $input -le 0 ]; then 847 | echo "输入有误, 请输入大于0的数字!" 848 | continue 849 | fi 850 | 851 | mtu=$input 852 | fi 853 | 854 | cat >&2 <<-EOF 855 | --------------------------- 856 | MTU = ${mtu} 857 | --------------------------- 858 | EOF 859 | break 860 | done 861 | } 862 | 863 | set_sndwnd() { 864 | while : 865 | do 866 | cat >&2 <<-'EOF' 867 | 868 | 请设置发送窗口大小(sndwnd) 869 | EOF 870 | read -p "(数据包数量, 默认: ${DEFAULT[SNDWND]}): " input 871 | echo 872 | if [ -n "$input" ]; then 873 | if ! is_number $input || [ $input -le 0 ]; then 874 | echo "输入有误, 请输入大于0的数字!" 875 | continue 876 | fi 877 | 878 | sndwnd=$input 879 | fi 880 | 881 | cat >&2 <<-EOF 882 | --------------------------- 883 | sndwnd = ${sndwnd} 884 | --------------------------- 885 | EOF 886 | break 887 | done 888 | } 889 | 890 | set_rcvwnd() { 891 | while : 892 | do 893 | cat >&2 <<-'EOF' 894 | 895 | 请设置接收窗口大小(rcvwnd) 896 | EOF 897 | read -p "(数据包数量, 默认: ${DEFAULT[RCVWND]}): " input 898 | echo 899 | if [ -n "$input" ]; then 900 | if ! is_number $input || [ $input -le 0 ]; then 901 | echo "输入有误, 请输入大于0的数字!" 902 | continue 903 | fi 904 | 905 | rcvwnd=$input 906 | fi 907 | 908 | cat >&2 <<-EOF 909 | --------------------------- 910 | rcvwnd = ${rcvwnd} 911 | --------------------------- 912 | EOF 913 | break 914 | done 915 | } 916 | 917 | set_datashard() { 918 | while : 919 | do 920 | cat >&2 <<-'EOF' 921 | 922 | 请设置前向纠错 datashard 923 | EOF 924 | read -p "(默认: ${DEFAULT[DATASHARD]}): " input 925 | echo 926 | if [ -n "$input" ]; then 927 | if ! is_number $input || [ $input -lt 0 ]; then 928 | echo "输入有误, 请输入大于等于0的数字!" 929 | continue 930 | fi 931 | 932 | datashard=$input 933 | fi 934 | 935 | cat >&2 <<-EOF 936 | --------------------------- 937 | datashard = ${datashard} 938 | --------------------------- 939 | EOF 940 | break 941 | done 942 | } 943 | 944 | set_parityshard() { 945 | while : 946 | do 947 | cat >&2 <<-'EOF' 948 | 949 | 请设置前向纠错 parityshard 950 | EOF 951 | read -p "(默认: ${DEFAULT[PARITYSHARD]}): " input 952 | echo 953 | if [ -n "$input" ]; then 954 | if ! is_number $input || [ $input -lt 0 ]; then 955 | echo "输入有误, 请输入大于等于0的数字!" 956 | continue 957 | fi 958 | 959 | parityshard=$input 960 | fi 961 | 962 | cat >&2 <<-EOF 963 | --------------------------- 964 | parityshard = ${parityshard} 965 | --------------------------- 966 | EOF 967 | break 968 | done 969 | } 970 | 971 | set_dscp() { 972 | while : 973 | do 974 | cat >&2 <<-'EOF' 975 | 976 | 请设置差分服务代码点(DSCP) 977 | EOF 978 | read -p "(默认: ${DEFAULT[DSCP]}): " input 979 | echo 980 | if [ -n "$input" ]; then 981 | if ! is_number $input || [ $input -lt 0 ]; then 982 | echo "输入有误, 请输入大于等于0的数字!" 983 | continue 984 | fi 985 | 986 | dscp=$input 987 | fi 988 | 989 | cat >&2 <<-EOF 990 | --------------------------- 991 | DSCP = ${dscp} 992 | --------------------------- 993 | EOF 994 | break 995 | done 996 | } 997 | 998 | set_nocomp() { 999 | while : 1000 | do 1001 | cat >&2 <<-'EOF' 1002 | 1003 | 是否禁用数据压缩? 1004 | EOF 1005 | read -p "(默认: 不禁用) [y/n]: " yn 1006 | echo 1007 | if [ -n "$yn" ]; then 1008 | case ${yn:0:1} in 1009 | y|Y) 1010 | nocomp=true 1011 | ;; 1012 | n|N) 1013 | nocomp=false 1014 | ;; 1015 | *) 1016 | echo "输入有误, 请重新输入!" 1017 | continue 1018 | ;; 1019 | esac 1020 | fi 1021 | 1022 | cat >&2 <<-EOF 1023 | --------------------------- 1024 | nocomp = ${nocomp} 1025 | --------------------------- 1026 | EOF 1027 | break 1028 | done 1029 | } 1030 | 1031 | # 设置隐藏参数 1032 | set_hidden_parameters() { 1033 | cat >&2 <<-'EOF' 1034 | 1035 | 开始配置隐藏参数... 1036 | EOF 1037 | set_acknodelay 1038 | set_sockbuf 1039 | set_keepalive 1040 | } 1041 | 1042 | set_acknodelay() { 1043 | while : 1044 | do 1045 | cat >&2 <<-'EOF' 1046 | 1047 | 是否启用 acknodelay 模式? 1048 | EOF 1049 | read -p "(默认: 不启用) [y/n]: " yn 1050 | echo 1051 | if [ -n "$yn" ]; then 1052 | case ${yn:0:1} in 1053 | y|Y) 1054 | acknodelay="true" 1055 | ;; 1056 | n|N) 1057 | acknodelay="false" 1058 | ;; 1059 | *) 1060 | echo "输入有误, 请重新输入!" 1061 | continue 1062 | ;; 1063 | esac 1064 | fi 1065 | 1066 | cat >&2 <<-EOF 1067 | --------------------------- 1068 | acknodelay = ${acknodelay} 1069 | --------------------------- 1070 | EOF 1071 | break 1072 | done 1073 | } 1074 | 1075 | set_sockbuf() { 1076 | while : 1077 | do 1078 | cat >&2 <<-'EOF' 1079 | 1080 | 请设置 UDP 收发缓冲区大小(sockbuf) 1081 | EOF 1082 | read -p "(单位: MB, 默认: $((${DEFAULT[SOCKBUF]} / 1024 / 1024))): " input 1083 | echo 1084 | if [ -n "$input" ]; then 1085 | if ! is_number $input || [ $input -le 0 ]; then 1086 | echo "输入有误, 请输入大于0的数字!" 1087 | continue 1088 | fi 1089 | 1090 | sockbuf=$(($input * 1024 * 1024)) 1091 | fi 1092 | 1093 | cat >&2 <<-EOF 1094 | --------------------------- 1095 | sockbuf = ${sockbuf} 1096 | --------------------------- 1097 | EOF 1098 | break 1099 | done 1100 | } 1101 | 1102 | set_keepalive() { 1103 | while : 1104 | do 1105 | cat >&2 <<-'EOF' 1106 | 1107 | 请设置 Keepalive 的间隔时间 1108 | EOF 1109 | read -p "(单位: s, 默认值: ${DEFAULT[KEEPALIVE]}, 前值: 5): " input 1110 | echo 1111 | if [ -n "$input" ]; then 1112 | if ! is_number $input || [ $input -le 0 ]; then 1113 | echo "输入有误, 请输入大于0的数字!" 1114 | continue 1115 | fi 1116 | 1117 | keepalive=$input 1118 | fi 1119 | 1120 | cat >&2 <<-EOF 1121 | --------------------------- 1122 | keepalive = ${keepalive} 1123 | --------------------------- 1124 | EOF 1125 | break 1126 | done 1127 | } 1128 | 1129 | # 设置运行用户 1130 | set_run_user() { 1131 | while : 1132 | do 1133 | cat >&2 <<-'EOF' 1134 | 1135 | 请设置以哪个用户运行当前 Kcptun 实例 1136 | EOF 1137 | read -p "(默认: ${DEFAULT[RUN_USER]}): " input 1138 | echo 1139 | if [ -n "$input" ]; then 1140 | if ! grep -q "^${input}:" /etc/passwd; then 1141 | echo "未发现该用户, 请先使用 useradd 手动创建用户 ${input}" 1142 | continue 1143 | fi 1144 | 1145 | if [ "$input" != "${DEFAULT[RUN_USER]}" -a "$listen_port" -lt 1024 ]; then 1146 | cat >&2 <<-EOF 1147 | 你设置的 Kcptun 监听端口为 ${listen_port} 1148 | 由于 linux 系统限制, 仅有 root 用户能启用小于 1024 的端口 1149 | 脚本已自动将用户设置为 root 1150 | EOF 1151 | input=${DEFAULT[RUN_USER]} 1152 | fi 1153 | 1154 | run_user=$input 1155 | fi 1156 | 1157 | cat >&2 <<-EOF 1158 | --------------------------- 1159 | 用户 = ${run_user} 1160 | --------------------------- 1161 | EOF 1162 | break 1163 | done 1164 | } 1165 | 1166 | # 设置参数 1167 | set_kcptun_config() { 1168 | echo 1169 | echo "开始配置参数..." 1170 | 1171 | set_listen_port 1172 | set_disable_ipv6 1173 | set_target_ip 1174 | set_target_port 1175 | set_key 1176 | set_crypt 1177 | set_mode 1178 | set_mtu 1179 | set_sndwnd 1180 | set_rcvwnd 1181 | set_datashard 1182 | set_parityshard 1183 | set_dscp 1184 | set_nocomp 1185 | set_run_user 1186 | 1187 | while : 1188 | do 1189 | cat >&2 <<-'EOF' 1190 | 1191 | 是否调整隐藏参数? 1192 | EOF 1193 | read -p "(默认: 否) [y/n]: " yn 1194 | echo 1195 | if [ -n "$yn" ]; then 1196 | case ${yn:0:1} in 1197 | y|Y) 1198 | set_hidden_parameters 1199 | ;; 1200 | n|N) 1201 | ;; 1202 | *) 1203 | echo "输入有误, 请重新输入!" 1204 | continue 1205 | ;; 1206 | esac 1207 | fi 1208 | break 1209 | done 1210 | 1211 | echo "配置完成, 按任意键继续...或者 Ctrl+C 取消" 1212 | any_key_to_continue 1213 | } 1214 | 1215 | # 安装需要的依赖软件 1216 | install_dependence() { 1217 | cat >&2 <<-'EOF' 1218 | 1219 | 正在安装依赖软件... 1220 | EOF 1221 | 1222 | if [ "$OS" = "CentOS" ]; then 1223 | yum makecache 1224 | yum update -y ca-certificates 1225 | yum install -y curl wget python-setuptools tar 1226 | else 1227 | apt-get -y update 1228 | apt-get -y install curl wget python-setuptools tar || { 1229 | cat >&2 <<-'EOF' 1230 | 1231 | 安装依赖软件包失败! 1232 | EOF 1233 | exit_with_error 1234 | } 1235 | fi 1236 | 1237 | [ ! -x "$JQ" ] && install_jq 1238 | 1239 | if ! easy_install supervisor; then 1240 | cat >&2 <<-'EOF' 1241 | 1242 | 安装 Supervisor 失败! 1243 | EOF 1244 | exit_with_error 1245 | fi 1246 | 1247 | [ -d /etc/supervisor/conf.d ] || mkdir -p /etc/supervisor/conf.d 1248 | 1249 | if [ ! -s /etc/supervisor/supervisord.conf ]; then 1250 | 1251 | if ! command_exists echo_supervisord_conf; then 1252 | cat >&2 <<-'EOF' 1253 | 1254 | 未找到 echo_supervisord_conf, 无法自动创建 Supervisor 配置文件! 1255 | 可能是当前安装的 supervisor 版本过低 1256 | EOF 1257 | exit_with_error 1258 | else 1259 | if ! echo_supervisord_conf > /etc/supervisor/supervisord.conf; then 1260 | cat >&2 <<-'EOF' 1261 | 1262 | 创建 Supervisor 配置文件失败! 1263 | EOF 1264 | exit_with_error 1265 | fi 1266 | fi 1267 | fi 1268 | } 1269 | 1270 | # 安装 Json 解析工具 JQ 1271 | install_jq() { 1272 | cat >&2 <<-'EOF' 1273 | 1274 | 正在安装 Json 解析工具 jq ... 1275 | EOF 1276 | local jq_url 1277 | if [ "$ARCH" = '64' ]; then 1278 | jq_url="$JQ_LINUX64" 1279 | else 1280 | jq_url="$JQ_LINUX32" 1281 | fi 1282 | 1283 | if ! wget --no-check-certificate -O "$JQ" "$jq_url"; then 1284 | cat >&2 <<-EOF 1285 | 1286 | 自动安装 jq 失败, 请手动下载安装! 1287 | 1288 | wget --no-check-certificate -O ${JQ} ${jq_url} 1289 | chmod a+x ${JQ} 1290 | 1291 | 安装完成之后请重新运行脚本 1292 | EOF 1293 | exit_with_error 1294 | fi 1295 | 1296 | chmod a+x "$JQ" 1297 | if [ ! -x "$JQ" ]; then 1298 | cat >&2 <<-EOF 1299 | 1300 | 无法设置执行权限, 请手动设置: 1301 | 1302 | chmod a+x ${JQ} 1303 | 1304 | 设置好之后请重新运行脚本 1305 | EOF 1306 | exit_with_error 1307 | fi 1308 | } 1309 | 1310 | # 通过网络获取需要的信息 1311 | get_kcptun_version_info() { 1312 | cat >&2 <<-'EOF' 1313 | 1314 | 正在获取网络信息... 1315 | EOF 1316 | 1317 | [ ! -x "$JQ" ] && install_jq 1318 | 1319 | local request_version=$1 1320 | local kcptun_release_content 1321 | 1322 | if [ -n "$request_version" ]; then 1323 | kcptun_release_content=$(curl --silent --insecure --fail $KCPTUN_RELEASES_URL | $JQ -r ".[] | select(.tag_name == \"${request_version}\")") 1324 | else 1325 | kcptun_release_content=$(curl --silent --insecure --fail $KCPTUN_RELEASES_URL | $JQ -r ".[0]") 1326 | fi 1327 | 1328 | if [ -n "$kcptun_release_content" ]; then 1329 | kcptun_release_name=$($JQ -r ".name" <<< "$kcptun_release_content") 1330 | kcptun_release_tag_name=$($JQ -r ".tag_name" <<< "$kcptun_release_content") 1331 | kcptun_release_prerelease=$($JQ -r ".prerelease" <<< "$kcptun_release_content") 1332 | kcptun_release_html_url=$($JQ -r ".html_url" <<< "$kcptun_release_content") 1333 | 1334 | kcptun_release_download_url=$($JQ -r ".assets[] | select(.name | contains(\"$SPRUCE_TYPE\")) | .browser_download_url" <<< "$kcptun_release_content" | head -n 1) || { 1335 | cat >&2 <<-'EOF' 1336 | 1337 | 获取 Kcptun 下载地址失败, 请重试... 1338 | EOF 1339 | exit_with_error 1340 | } 1341 | else 1342 | if [ -n "$request_version" ]; then 1343 | return 2 1344 | else 1345 | cat >&2 <<-'EOF' 1346 | 1347 | 获取 Kcptun 版本信息失败, 请检查你的网络连接! 1348 | EOF 1349 | exit_with_error 1350 | fi 1351 | fi 1352 | } 1353 | 1354 | # 获取shell脚本更新 1355 | get_shell_version_info() { 1356 | local shell_version_content=$(curl --silent --insecure --fail $SHELL_VERSION_INFO_URL) 1357 | if [ $? -eq 0 ]; then 1358 | new_shell_version=$($JQ -r ".shell_version" <<< "$shell_version_content" | grep -oE "[0-9]+" ) 1359 | new_config_version=$($JQ -r ".config_version" <<< "$shell_version_content" | grep -oE "[0-9]+" ) 1360 | new_init_version=$($JQ -r ".init_version" <<< "$shell_version_content" | grep -oE "[0-9]+") 1361 | 1362 | shell_change_log=$($JQ -r ".change_log" <<< "$shell_version_content") 1363 | config_change_log=$($JQ -r ".config_change_log" <<< "$shell_version_content") 1364 | init_change_log=$($JQ -r ".init_change_log" <<< "$shell_version_content") 1365 | 1366 | new_shell_url=$($JQ -r ".shell_url" <<< "$shell_version_content") 1367 | else 1368 | new_shell_version=0 1369 | new_config_version=0 1370 | new_init_version=0 1371 | fi 1372 | } 1373 | 1374 | # 下载文件 1375 | download_file(){ 1376 | cat >&2 <<-'EOF' 1377 | 1378 | 开始下载文件... 1379 | EOF 1380 | 1381 | cd "$CUR_DIR" 1382 | if [ `pwd` != "$CUR_DIR" ]; then 1383 | cat >&2 <<-'EOF' 1384 | 1385 | 切换目录失败... 1386 | EOF 1387 | exit_with_error 1388 | fi 1389 | 1390 | kcptun_file_name="kcptun-${kcptun_release_tag_name}.tar.gz" 1391 | if [ -f "$kcptun_file_name" ] && tar -tf "$kcptun_file_name" &>/dev/null; then 1392 | cat >&2 <<-'EOF' 1393 | 1394 | 已找到 Kcptun 文件压缩包, 跳过下载... 1395 | EOF 1396 | return 0 1397 | fi 1398 | 1399 | if ! wget --no-check-certificate -c -t 3 -O "$kcptun_file_name" "$kcptun_release_download_url"; then 1400 | cat >&2 <<-EOF 1401 | 1402 | 下载 Kcptun 文件压缩包失败, 你可以尝试手动下载文件: 1403 | 1. 下载 ${kcptun_release_download_url} 1404 | 2. 将文件重命名为 ${file_name} 1405 | 3. 上传文件至脚本当前目录 ${CUR_DIR} 1406 | 4. 重新运行脚本开始安装 1407 | EOF 1408 | exit_with_error 1409 | fi 1410 | 1411 | } 1412 | 1413 | # 解压文件 1414 | unpack_file() { 1415 | cat >&2 <<-'EOF' 1416 | 1417 | 开始解压文件... 1418 | EOF 1419 | 1420 | cd "$CUR_DIR" 1421 | [ -d "$KCPTUN_INSTALL_DIR" ] || mkdir -p "$KCPTUN_INSTALL_DIR" 1422 | tar -zxf "$kcptun_file_name" -C "$KCPTUN_INSTALL_DIR" 1423 | 1424 | local kcptun_server_exec="$KCPTUN_INSTALL_DIR"/server_"$FILE_SUFFIX" 1425 | if [ -f "$kcptun_server_exec" ]; then 1426 | if ! chmod a+x "$kcptun_server_exec"; then 1427 | cat >&2 <<-'EOF' 1428 | 1429 | 无法设置执行权限... 1430 | EOF 1431 | exit_with_error 1432 | fi 1433 | else 1434 | cat >&2 <<-'EOF' 1435 | 1436 | 未在解压文件中找到 Kcptun 服务端执行文件, 请重试! 1437 | EOF 1438 | exit_with_error 1439 | fi 1440 | } 1441 | 1442 | # 创建配置文件 1443 | config_kcptun() { 1444 | cat >&2 <<-'EOF' 1445 | 1446 | 正在写入配置... 1447 | EOF 1448 | 1449 | if [ -f /etc/supervisor/supervisord.conf ]; then 1450 | # sed -i 's/^\[include\]$/&\nfiles = \/etc\/supervisor\/conf.d\/\*\.conf/; \ 1451 | # t;$a [include]\nfiles = /etc/supervisor/conf.d/*.conf' /etc/supervisor/supervisord.conf 1452 | 1453 | $(grep -q "^files\s*=\s*\/etc\/supervisor\/conf\.d\/\*\.conf$" /etc/supervisor/supervisord.conf) || { 1454 | if grep -q "^\[include\]$" /etc/supervisor/supervisord.conf; then 1455 | sed -i '/^\[include\]$/a files = \/etc\/supervisor\/conf.d\/\*\.conf' /etc/supervisor/supervisord.conf 1456 | else 1457 | sed -i '$a [include]\nfiles = /etc/supervisor/conf.d/*.conf' /etc/supervisor/supervisord.conf 1458 | fi 1459 | } 1460 | 1461 | # 创建文件夹 1462 | [ -d "$KCPTUN_INSTALL_DIR" ] || mkdir -p "$KCPTUN_INSTALL_DIR" 1463 | 1464 | local config_file="$(get_current_config_file)" 1465 | local supervisor_config_file="$(get_current_supervisor_config_file)" 1466 | 1467 | cat > "$config_file"<<-EOF 1468 | { 1469 | "listen": "${listen_addr}:${listen_port}", 1470 | "target": "${target_ip}:${target_port}", 1471 | "key": "${key}", 1472 | "crypt": "${crypt}", 1473 | "mode": "${mode}", 1474 | "mtu": ${mtu}, 1475 | "sndwnd": ${rcvwnd}, 1476 | "rcvwnd": ${sndwnd}, 1477 | "datashard": ${datashard}, 1478 | "parityshard": ${parityshard}, 1479 | "dscp": ${dscp}, 1480 | "nocomp": ${nocomp}, 1481 | "acknodelay": ${acknodelay}, 1482 | "nodelay": ${nodelay}, 1483 | "interval": ${interval}, 1484 | "resend": ${resend}, 1485 | "nc": ${nc}, 1486 | "sockbuf": ${sockbuf}, 1487 | "keepalive": ${keepalive} 1488 | } 1489 | EOF 1490 | 1491 | cat > "$supervisor_config_file"<<-EOF 1492 | [program:kcptun${current_id}] 1493 | user=${run_user} 1494 | directory=${KCPTUN_INSTALL_DIR} 1495 | command=${KCPTUN_INSTALL_DIR}/server_${FILE_SUFFIX} -c "${config_file}" 1496 | process_name=%(program_name)s 1497 | autostart=true 1498 | redirect_stderr=true 1499 | stdout_logfile=$(get_current_log_file) 1500 | stdout_logfile_maxbytes=1MB 1501 | stdout_logfile_backups=0 1502 | EOF 1503 | else 1504 | cat >&2 <<-'EOF' 1505 | 1506 | 未找到 Supervisor 配置文件! 1507 | 请先使用脚本安装 Kcptun 服务端 1508 | EOF 1509 | exit_with_error 1510 | fi 1511 | } 1512 | 1513 | # 下载服务脚本 1514 | downlod_init_script() { 1515 | cat >&2 <<-'EOF' 1516 | 1517 | 开始下载服务脚本... 1518 | EOF 1519 | 1520 | local init_file_url 1521 | if [ "$OS" = "CentOS" ]; then 1522 | init_file_url="https://raw.githubusercontent.com/kuoruan/kcptun_installer/master/redhat.init" 1523 | else 1524 | init_file_url="https://raw.githubusercontent.com/kuoruan/kcptun_installer/master/ubuntu.init" 1525 | fi 1526 | 1527 | if ! wget --no-check-certificate -O /etc/init.d/supervisord "$init_file_url"; then 1528 | cat >&2 <<-'EOF' 1529 | 1530 | 下载 Supervisor init 脚本失败! 1531 | EOF 1532 | exit_with_error 1533 | fi 1534 | 1535 | if ! chmod a+x /etc/init.d/supervisord; then 1536 | cat >&2 <<-'EOF' 1537 | 1538 | 设置执行权限失败... 1539 | EOF 1540 | exit_with_error 1541 | fi 1542 | } 1543 | 1544 | # 安装服务 1545 | install_service() { 1546 | cat >&2 <<-'EOF' 1547 | 1548 | 正在配置系统服务... 1549 | EOF 1550 | 1551 | if [ "$OS" = "CentOS" ]; then 1552 | chkconfig --add supervisord 1553 | chkconfig supervisord on 1554 | else 1555 | update-rc.d -f supervisord defaults 1556 | fi 1557 | 1558 | restart_supervisor 1559 | } 1560 | 1561 | # 设置防火墙 1562 | config_firewall() { 1563 | cat >&2 <<-'EOF' 1564 | 1565 | 开始设置防火墙... 1566 | EOF 1567 | 1568 | if command_exists iptables; then 1569 | if service iptables status >/dev/null 2>&1; then 1570 | if [ -n "$current_listen_port" ]; then 1571 | iptables -D INPUT -p udp --dport ${current_listen_port} -j ACCEPT >/dev/null 2>&1 1572 | fi 1573 | iptables -nL | grep "$listen_port" | grep -q "ACCEPT" 1574 | if [ $? -ne 0 ]; then 1575 | iptables -I INPUT -p udp --dport ${listen_port} -j ACCEPT 1576 | service iptables save 1577 | service iptables restart 1578 | fi 1579 | 1580 | cat >&2 <<-EOF 1581 | 1582 | UDP 端口 ${listen_port} 已开放! 1583 | EOF 1584 | else 1585 | cat >&2 <<-EOF 1586 | 1587 | iptables 未启动或未配置 1588 | 如有必要, 请手动添加端口 ${listen_port} 的防火墙规则: 1589 | 1590 | iptables -I INPUT -p udp --dport ${listen_port} -j ACCEPT 1591 | service iptables save 1592 | service iptables restart 1593 | EOF 1594 | fi 1595 | else 1596 | cat >&2 <<-EOF 1597 | 1598 | iptables 未安装, 跳过配置 1599 | EOF 1600 | fi 1601 | 1602 | if command_exists firewall-cmd; then 1603 | if systemctl status firewalld >/dev/null 2>&1; then 1604 | if [ -n "$current_listen_port" ]; then 1605 | firewall-cmd --zone=public --remove-port=${current_listen_port}/udp >/dev/null 2>&1 1606 | fi 1607 | firewall-cmd --zone=public --query-port=${listen_port}/udp >/dev/null 2>&1 1608 | if [ $? -ne 0 ]; then 1609 | firewall-cmd --permanent --zone=public --add-port=${listen_port}/udp 1610 | firewall-cmd --reload 1611 | fi 1612 | cat >&2 <<-EOF 1613 | 1614 | UDP 端口 ${listen_port} 已开放! 1615 | EOF 1616 | else 1617 | cat >&2 <<-EOF 1618 | 1619 | firewalld 未启动或未配置 1620 | 如果有必要, 请手动添加端口 ${listen_port} 的防火墙规则: 1621 | 1622 | firewall-cmd --permanent --zone=public --add-port=${listen_port}/udp 1623 | firewall-cmd --reload 1624 | EOF 1625 | fi 1626 | else 1627 | cat >&2 <<-'EOF' 1628 | 1629 | firewalld 未安装, 跳过配置 1630 | EOF 1631 | fi 1632 | } 1633 | 1634 | # 安装清理 1635 | install_cleanup() { 1636 | cat >&2 <<-'EOF' 1637 | 1638 | 正在清理无用文件... 1639 | EOF 1640 | 1641 | cd "$CUR_DIR" 1642 | rm -f "$kcptun_file_name" 1643 | rm -f "$KCPTUN_INSTALL_DIR"/client_"$FILE_SUFFIX" 1644 | } 1645 | 1646 | # 显示配置信息 1647 | show_config_info() { 1648 | echo 1649 | echo -e "服务器IP: \033[41;37m ${SERVER_IP} \033[0m" 1650 | echo -e "端口: \033[41;37m ${listen_port} \033[0m" 1651 | echo -e "加速地址: ${target_ip}:${target_port}" 1652 | [ "$key" != "${DEFAULT[KEY]}" ] && echo -e "密码: \033[41;37m ${key} \033[0m" 1653 | [ "$crypt" != "${DEFAULT[CRYPT]}" ] && echo -e "crypt: \033[41;37m ${crypt} \033[0m" 1654 | [ "$mode" != "${DEFAULT[MODE]}" ] && echo -e "mode: \033[41;37m ${mode} \033[0m" 1655 | [ "$mtu" != "${DEFAULT[MTU]}" ] && echo -e "mtu: \033[41;37m ${mtu} \033[0m" 1656 | echo -e "sndwnd: \033[41;37m ${sndwnd} \033[0m" 1657 | echo -e "rcvwnd: \033[41;37m ${rcvwnd} \033[0m" 1658 | [ "$datashard" != "${DEFAULT[DATASHARD]}" ] && echo -e "datashard: \033[41;37m ${datashard} \033[0m" 1659 | [ "$parityshard" != "${DEFAULT[PARITYSHARD]}" ] && echo -e "parityshard: \033[41;37m ${parityshard} \033[0m" 1660 | [ "$dscp" != "${DEFAULT[DSCP]}" ] && echo -e "dscp: \033[41;37m ${dscp} \033[0m" 1661 | [ "$nocomp" != "${DEFAULT[NOCOMP]}" ] && echo -e "nocomp: \033[41;37m ${nocomp} \033[0m" 1662 | [ "$nodelay" != "${DEFAULT[NODELAY]}" ] && echo -e "nodelay: \033[41;37m ${nodelay} \033[0m" 1663 | [ "$interval" != "${DEFAULT[INTERVAL]}" ] && echo -e "interval: \033[41;37m ${interval} \033[0m" 1664 | [ "$resend" != "${DEFAULT[RESEND]}" ] && echo -e "resend: \033[41;37m ${resend} \033[0m" 1665 | [ "$nc" != "${DEFAULT[NC]}" ] && echo -e "nc: \033[41;37m ${nc} \033[0m" 1666 | [ "$acknodelay" != "${DEFAULT[ACKNODELAY]}" ] && echo -e "acknodelay: \033[41;37m ${acknodelay} \033[0m" 1667 | [ "$sockbuf" != "${DEFAULT[SOCKBUF]}" ] && echo -e "sockbuf: \033[41;37m ${sockbuf} \033[0m" 1668 | [ "$keepalive" != "${DEFAULT[KEEPALIVE]}" ] && echo -e "keepalive: \033[41;37m ${keepalive} \033[0m" 1669 | } 1670 | 1671 | # 处理手机端参数 1672 | generate_mobile_args() { 1673 | kcptun_mobile_args="-autoexpire 60" 1674 | 1675 | [ "$key" != "${DEFAULT[KEY]}" ] && kcptun_mobile_args="${kcptun_mobile_args} -key \"${key}\"" 1676 | [ "$crypt" != "${DEFAULT[CRYPT]}" ] && kcptun_mobile_args="${kcptun_mobile_args} -crypt \"${crypt}\"" 1677 | [ "$mode" != "${DEFAULT[MODE]}" ] && kcptun_mobile_args="${kcptun_mobile_args} -mode \"${mode}\"" 1678 | [ "$mtu" != "${DEFAULT[MTU]}" ] && kcptun_mobile_args="${kcptun_mobile_args} -mtu ${mtu}" 1679 | [ "$datashard" != "${DEFAULT[DATASHARD]}" ] && kcptun_mobile_args="${kcptun_mobile_args} -datashard ${datashard}" 1680 | [ "$parityshard" != "${DEFAULT[PARITYSHARD]}" ] && kcptun_mobile_args="${kcptun_mobile_args} -parityshard ${parityshard}" 1681 | [ "$dscp" != "${DEFAULT[DSCP]}" ] && kcptun_mobile_args="${kcptun_mobile_args} -dscp ${dscp}" 1682 | [ "$nocomp" != "${DEFAULT[NOCOMP]}" ] && kcptun_mobile_args="${kcptun_mobile_args} -nocomp" 1683 | [ "$nodelay" != "${DEFAULT[NODELAY]}" ] && kcptun_mobile_args="${kcptun_mobile_args} -nodelay ${nodelay}" 1684 | [ "$interval" != "${DEFAULT[INTERVAL]}" ] && kcptun_mobile_args="${kcptun_mobile_args} -interval ${interval}" 1685 | [ "$resend" != "${DEFAULT[RESEND]}" ] && kcptun_mobile_args="${kcptun_mobile_args} -resend ${resend}" 1686 | [ "$nc" != "${DEFAULT[NC]}" ] && kcptun_mobile_args="${kcptun_mobile_args} -nc ${nc}" 1687 | [ "$acknodelay" != "${DEFAULT[ACKNODELAY]}" ] && kcptun_mobile_args="${kcptun_mobile_args} -acknodelay" 1688 | [ "$sockbuf" != "${DEFAULT[SOCKBUF]}" ] && kcptun_mobile_args="${kcptun_mobile_args} -sockbuf ${sockbuf}" 1689 | [ "$keepalive" != "${DEFAULT[KEEPALIVE]}" ] && kcptun_mobile_args="${kcptun_mobile_args} -keepalive ${keepalive}" 1690 | } 1691 | 1692 | show_recommend_config() { 1693 | cat >&2 <<-EOF 1694 | 1695 | 可使用的客户端配置文件为: 1696 | { 1697 | "localaddr": ":${target_port}", 1698 | "remoteaddr": "${SERVER_IP}:${listen_port}", 1699 | "key": "${key}", 1700 | "crypt": "${crypt}", 1701 | "mode": "${mode}", 1702 | "conn": 1, 1703 | "autoexpire": 60, 1704 | "mtu": ${mtu}, 1705 | "sndwnd": ${rcvwnd}, 1706 | "rcvwnd": ${sndwnd}, 1707 | "datashard": ${datashard}, 1708 | "parityshard": ${parityshard}, 1709 | "dscp": ${dscp}, 1710 | "nocomp": ${nocomp}, 1711 | "acknodelay": ${acknodelay}, 1712 | "nodelay": ${nodelay}, 1713 | "interval": ${interval}, 1714 | "resend": ${resend}, 1715 | "nc": ${nc}, 1716 | "sockbuf": ${sockbuf}, 1717 | "keepalive": ${keepalive} 1718 | } 1719 | 1720 | 手机端参数可以使用: 1721 | ${kcptun_mobile_args} 1722 | 1723 | 各参数详细说明可以查看: https://github.com/xtaci/kcptun 1724 | EOF 1725 | } 1726 | 1727 | # 显示安装信息 1728 | show_installed_info() { 1729 | show_config_info 1730 | show_installed_version 1731 | show_recommend_config 1732 | 1733 | cat >&2 <<-EOF 1734 | 1735 | Kcptun 安装目录: ${KCPTUN_INSTALL_DIR} 1736 | Kcptun 日志目录: ${KCPTUN_LOG_DIR} 1737 | 1738 | 已将 Supervisor 加入开机自启, Kcptun 服务端会随 Supervisor 的启动而启动 1739 | 1740 | 更多使用说明: ${0} help 1741 | 1742 | 欢迎访问扩软博客: https://blog.kuoruan.com/ 1743 | 我们的QQ群: 43391448 1744 | 1745 | 尽情使用吧! 1746 | EOF 1747 | } 1748 | 1749 | get_new_instance_id() { 1750 | if [ -f "/etc/supervisor/conf.d/kcptun.conf" ]; then 1751 | local i=2 1752 | while [ -f "/etc/supervisor/conf.d/kcptun${i}.conf" ] 1753 | do 1754 | let i++ 1755 | done 1756 | echo "$i" 1757 | fi 1758 | } 1759 | 1760 | # 添加实例 1761 | add_instance() { 1762 | permission_check 1763 | linux_check 1764 | get_arch 1765 | get_server_ip 1766 | 1767 | cat >&2 <<-'EOF' 1768 | 1769 | 你选择了添加实例, 正在开始操作... 1770 | EOF 1771 | 1772 | current_id="$(get_new_instance_id)" 1773 | 1774 | set_kcptun_config 1775 | config_kcptun 1776 | config_firewall 1777 | restart_supervisor 1778 | get_installed_version 1779 | generate_mobile_args 1780 | 1781 | cat >&2 <<-EOF 1782 | 1783 | 恭喜, 实例 kcptun${current_id} 添加成功! 1784 | EOF 1785 | 1786 | show_config_info 1787 | show_installed_version 1788 | show_recommend_config 1789 | } 1790 | 1791 | # 删除实例 1792 | del_instance() { 1793 | permission_check 1794 | linux_check 1795 | get_arch 1796 | 1797 | if [ -n "$1" ]; then 1798 | if is_number $1; then 1799 | if [ $1 -ne 1 ]; then 1800 | current_id="$1" 1801 | fi 1802 | else 1803 | cat >&2 <<-EOF 1804 | 1805 | 参数有误, 请使用 $0 del 1806 | 为实例ID, 当前共有 $(get_instance_count) 个实例 1807 | EOF 1808 | 1809 | exit 1 1810 | fi 1811 | fi 1812 | 1813 | cat >&2 <<-EOF 1814 | 1815 | 你选择了删除实例 kcptun${current_id}, 实例配置文件删除后无法恢复 1816 | 按任意键继续...或者 Ctrl+C 取消 1817 | EOF 1818 | any_key_to_continue 1819 | 1820 | local supervisor_config_file="$(get_current_supervisor_config_file)" 1821 | if [ ! -f "$supervisor_config_file" ]; then 1822 | cat >&2 <<-EOF 1823 | 1824 | 你选择的实例 kcptun${current_id} 不存在! 1825 | EOF 1826 | exit 1 1827 | fi 1828 | 1829 | rm -f "$supervisor_config_file" 1830 | rm -f "$(get_current_config_file)" 1831 | rm -f "$(get_current_log_file)" 1832 | restart_supervisor 1833 | 1834 | cat >&2 <<-EOF 1835 | 1836 | 实例 kcptun${current_id} 删除成功! 1837 | EOF 1838 | } 1839 | 1840 | # 安装 Kcptun 1841 | install_kcptun() { 1842 | permission_check 1843 | linux_check 1844 | installed_check 1845 | disable_selinux 1846 | get_arch 1847 | get_server_ip 1848 | set_kcptun_config 1849 | install_dependence 1850 | get_kcptun_version_info 1851 | download_file 1852 | unpack_file 1853 | config_kcptun 1854 | downlod_init_script 1855 | install_service 1856 | config_firewall 1857 | install_cleanup 1858 | get_installed_version 1859 | generate_mobile_args 1860 | show_installed_info 1861 | } 1862 | 1863 | # 重新下载 kcptun 1864 | update_kcptun() { 1865 | download_file 1866 | unpack_file 1867 | restart_supervisor 1868 | install_cleanup 1869 | show_installed_version 1870 | 1871 | cat >&2 <<-EOF 1872 | 1873 | 恭喜, Kcptun 服务端更新完毕! 1874 | EOF 1875 | } 1876 | 1877 | #手动安装 1878 | manual_install() { 1879 | permission_check 1880 | linux_check 1881 | get_arch 1882 | 1883 | cat >&2 <<-'EOF' 1884 | 1885 | 你选择了自定义版本安装, 正在开始操作... 1886 | EOF 1887 | 1888 | local tag_name=$1 1889 | while : 1890 | do 1891 | if [ -z "$tag_name" ]; then 1892 | cat >&2 <<-'EOF' 1893 | 1894 | 请输入你想安装的 Kcptun 版本的完整 TAG 1895 | EOF 1896 | read -p "(例如: v20160904): " tag_name 1897 | echo 1898 | if $(grep -qE "\w+" <<< "$tag_name"); then 1899 | 1900 | if [ "$tag_name" = "SNMP_Milestone" ]; then 1901 | echo "不支持此版本, 请重新输入!" 1902 | unset tag_name 1903 | continue 1904 | fi 1905 | 1906 | local version_num 1907 | version_num=$(grep -oE "[0-9]+" <<< "$tag_name") || version_num=0 1908 | if [ ${#version_num} -eq 8 -a $version_num -le 20160826 ]; then 1909 | echo "暂不支持安装 v20160826 及以前版本" 1910 | continue 1911 | fi 1912 | else 1913 | echo "输入无效, 请重新输入!" 1914 | continue 1915 | fi 1916 | fi 1917 | 1918 | get_kcptun_version_info $tag_name 1919 | if [ $? -eq 2 ]; then 1920 | cat >&2 <<-EOF 1921 | 未找到对应版本下载地址 (TAG: ${tag_name}), 请重新输入! 1922 | 你可以前往: ${KCPTUN_TAGS_URL} 查看所有可用 TAG 1923 | EOF 1924 | unset tag_name 1925 | continue 1926 | else 1927 | cat >&2 <<-EOF 1928 | 已找到 Kcptun 版本信息, TAG: ${tag_name} 1929 | 请按任意键继续安装... 1930 | EOF 1931 | any_key_to_continue 1932 | update_kcptun 1933 | break 1934 | fi 1935 | done 1936 | } 1937 | 1938 | # 选择一个实例 1939 | select_instance() { 1940 | 1941 | if [ $(get_instance_count) -gt 1 ]; then 1942 | cat >&2 <<-'EOF' 1943 | 1944 | 当前有多个 Kcptun 实例 (按最后修改时间排序): 1945 | EOF 1946 | 1947 | local files=$(ls -lt /etc/supervisor/conf.d/ | grep "^-" | awk '{print $9}' | grep -P "^kcptun\d*\.conf$") 1948 | local i=0 1949 | local array=() 1950 | for file in $files 1951 | do 1952 | let i++ 1953 | array[$i]=$(grep -oP "\d+" <<<"$file") 1954 | echo "(${i}) "${file%.*} 1955 | done 1956 | 1957 | while : 1958 | do 1959 | read -p "(默认: 1) 请选择 [1~${i}]: " sel 1960 | if [ -n "$sel" ]; then 1961 | if is_number $sel && [ $sel -ge 1 -a $sel -le $i ]; then 1962 | current_id=${array[$sel]} 1963 | else 1964 | cat >&2 <<-EOF 1965 | 1966 | 请输入有效数字 1~${i}! 1967 | EOF 1968 | continue 1969 | fi 1970 | fi 1971 | break 1972 | done 1973 | fi 1974 | } 1975 | 1976 | # 加载实例配置信息 1977 | load_instance_config() { 1978 | local config_file="$(get_current_config_file)" 1979 | 1980 | if [ ! -s "$config_file" ]; then 1981 | cat >&2 <<-'EOF' 1982 | 1983 | 实例配置文件不存在或为空, 请检查! 1984 | EOF 1985 | 1986 | exit 1 1987 | fi 1988 | 1989 | [ ! -x "$JQ" ] && install_jq 1990 | 1991 | if ! $($JQ -r '.' "$config_file" >/dev/null 2>&1); then 1992 | cat >&2 <<-EOF 1993 | 1994 | 实例配置文件存在错误, 请检查! 1995 | 配置文件路径: ${config_file} 1996 | EOF 1997 | exit 1 1998 | fi 1999 | 2000 | local lines=$($JQ -r 'to_entries | map("\(.key)=\(.value | @sh)") | .[]' "$config_file") 2001 | 2002 | while read -r line 2003 | do 2004 | eval "$line" 2005 | done <<< "$lines" 2006 | 2007 | [ -n "$listen" ] && listen_port=$(cut -d ':' -f2 <<< "$listen") 2008 | if [ -n "$target" ]; then 2009 | target_ip=$(cut -d ':' -f1 <<< "$target") 2010 | target_port=$(cut -d ':' -f2 <<< "$target") 2011 | fi 2012 | } 2013 | 2014 | # 显示配置信息 2015 | show_instance_config() { 2016 | permission_check 2017 | get_arch 2018 | 2019 | if [ -n "$1" ]; then 2020 | if is_number $1; then 2021 | if [ $1 -ne 1 ]; then 2022 | current_id="$1" 2023 | fi 2024 | else 2025 | cat >&2 <<-EOF 2026 | 2027 | 参数有误, 请使用 $0 show 2028 | 为实例ID, 当前共有 $(get_instance_count) 个实例 2029 | EOF 2030 | 2031 | exit 1 2032 | fi 2033 | fi 2034 | 2035 | cat >&2 <<-EOF 2036 | 2037 | 你选择了查看实例 kcptun${current_id} 的配置, 正在读取... 2038 | EOF 2039 | get_server_ip 2040 | load_instance_config 2041 | get_installed_version 2042 | generate_mobile_args 2043 | 2044 | cat >&2 <<-EOF 2045 | 2046 | 实例 kcptun${current_id} 的配置信息如下: 2047 | EOF 2048 | show_config_info 2049 | show_installed_version 2050 | show_recommend_config 2051 | } 2052 | 2053 | # 显示实例日志 2054 | show_instance_log() { 2055 | permission_check 2056 | 2057 | if [ -n "$1" ]; then 2058 | if is_number $1; then 2059 | if [ $1 -ne 1 ]; then 2060 | current_id="$1" 2061 | fi 2062 | else 2063 | cat >&2 <<-EOF 2064 | 2065 | 参数有误, 请使用 $0 log 2066 | 为实例ID, 当前共有 $(get_instance_count) 个实例 2067 | EOF 2068 | 2069 | exit 1 2070 | fi 2071 | fi 2072 | 2073 | cat >&2 <<-EOF 2074 | 2075 | 你选择了查看实例 kcptun${current_id} 的日志, 正在读取... 2076 | EOF 2077 | 2078 | local log_file="$(get_current_log_file)" 2079 | 2080 | if [ -f "$log_file" ]; then 2081 | cat >&2 <<-EOF 2082 | 2083 | 实例 kcptun${current_id} 的日志信息如下: 2084 | 注: 日志实时刷新, 按 Ctrl+C 退出日志查看 2085 | EOF 2086 | tail -n 20 -f "$log_file" 2087 | else 2088 | cat >&2 <<-EOF 2089 | 2090 | 未找到实例 kcptun${current_id} 的日志文件... 2091 | EOF 2092 | 2093 | exit 1 2094 | fi 2095 | } 2096 | 2097 | show_installed_version() { 2098 | cat >&2 <<-EOF 2099 | 2100 | 当前安装的 Kcptun 版本为: ${installed_kcptun_version} 2101 | $([ -n "$kcptun_release_html_url" ] && echo "请前往 ${kcptun_release_html_url} 手动下载客户端文件") 2102 | EOF 2103 | } 2104 | 2105 | get_installed_version() { 2106 | cat >&2 <<-'EOF' 2107 | 2108 | 正在获取当前安装的 Kcptun 信息... 2109 | EOF 2110 | 2111 | local kcptun_server_exec="$KCPTUN_INSTALL_DIR"/server_"$FILE_SUFFIX" 2112 | if [ -x "$kcptun_server_exec" ]; then 2113 | installed_kcptun_version=$(${kcptun_server_exec} -v | awk '{printf $3}') 2114 | else 2115 | unset installed_kcptun_version 2116 | cat >&2 <<-'EOF' 2117 | 2118 | 未找到已安装的 Kcptun 服务端执行文件, 或许你并没有安装 Kcptun? 2119 | 请运行脚本来重新安装 Kcptun 服务端 2120 | EOF 2121 | exit_with_error 2122 | fi 2123 | } 2124 | 2125 | # 检查更新 2126 | check_update() { 2127 | permission_check 2128 | linux_check 2129 | get_arch 2130 | cat >&2 <<-EOF 2131 | 2132 | 你选择了检查更新, 正在开始操作... 2133 | EOF 2134 | 2135 | local shell_path=$0 2136 | get_shell_version_info 2137 | 2138 | if [ -n "$new_shell_version" -a $new_shell_version -gt $SHELL_VERSION ]; then 2139 | cat >&2 <<-EOF 2140 | 2141 | 发现一键安装脚本更新, 版本号: ${new_shell_version} 2142 | $(echo -e "更新说明: \n${shell_change_log}") 2143 | 2144 | 按任意键开始更新, 或者 Ctrl+C 取消 2145 | EOF 2146 | any_key_to_continue 2147 | echo "正在更新一键安装脚本..." 2148 | mv -f "$shell_path" "$shell_path".bak 2149 | 2150 | if wget --no-check-certificate -O "$shell_path" "$new_shell_url"; then 2151 | chmod a+x "$shell_path" 2152 | sed -i -r "s/^CONFIG_VERSION=[0-9]+/CONFIG_VERSION=${CONFIG_VERSION}/" "$shell_path" 2153 | sed -i -r "s/^INIT_VERSION=[0-9]+/INIT_VERSION=${INIT_VERSION}/" "$shell_path" 2154 | rm -f "$shell_path".bak 2155 | clear 2156 | cat >&2 <<-EOF 2157 | 2158 | 安装脚本已更新到 v${new_shell_version}, 正在运行新的脚本... 2159 | EOF 2160 | 2161 | bash $shell_path update 2162 | exit 0 2163 | else 2164 | mv -f "$shell_path".bak $shell_path 2165 | 2166 | cat >&2 <<-'EOF' 2167 | 2168 | 下载新的一键安装脚本失败... 2169 | EOF 2170 | fi 2171 | else 2172 | cat >&2 <<-'EOF' 2173 | 2174 | 未发现一键安装脚本更新... 2175 | EOF 2176 | fi 2177 | 2178 | get_installed_version 2179 | get_kcptun_version_info 2180 | 2181 | local cur_tag_name="$installed_kcptun_version" 2182 | 2183 | if [ -n "$cur_tag_name" ] && is_number $cur_tag_name && [ ${#cur_tag_name} -eq 8 ]; then 2184 | cur_tag_name=v"$cur_tag_name" 2185 | fi 2186 | 2187 | if [ -n "$kcptun_release_tag_name" -a "$kcptun_release_tag_name" != "$cur_tag_name" ]; then 2188 | cat >&2 <<-EOF 2189 | 2190 | 发现 Kcptun 新版本 ${kcptun_release_tag_name} 2191 | $(echo -e "更新说明: \n${kcptun_release_name}") 2192 | $([ "$kcptun_release_prerelease" = "true" ] && echo -e "\033[41;37m 注意: 该版本为预览版, 请谨慎更新 \033[0m") 2193 | 2194 | 按任意键开始更新, 或者 Ctrl+C 取消 2195 | EOF 2196 | any_key_to_continue 2197 | echo "正在自动更新 Kcptun..." 2198 | update_kcptun 2199 | else 2200 | cat >&2 <<-'EOF' 2201 | 2202 | 未发现 Kcptun 更新... 2203 | EOF 2204 | fi 2205 | 2206 | if [ -n "$new_config_version" -a $new_config_version -gt $CONFIG_VERSION ]; then 2207 | cat >&2 <<-EOF 2208 | 2209 | 发现 Kcptun 配置更新, 版本号: v${new_config_version}, 需要重新设置 Kcptun... 2210 | $(echo -e "更新说明: \n${config_change_log}") 2211 | 2212 | 按任意键开始配置, 或者 Ctrl+C 取消 2213 | EOF 2214 | any_key_to_continue 2215 | reconfig_instance 2216 | sed -i "s/^CONFIG_VERSION=${CONFIG_VERSION}/CONFIG_VERSION=${new_config_version}/" "$shell_path" 2217 | else 2218 | cat >&2 <<-'EOF' 2219 | 2220 | 未发现 Kcptun 配置更新... 2221 | EOF 2222 | fi 2223 | 2224 | if [ -n "$new_init_version" -a $new_init_version -gt $INIT_VERSION ]; then 2225 | cat >&2 <<-EOF 2226 | 2227 | 发现服务启动脚本文件更新, 版本号: v${new_init_version} 2228 | $(echo -e "更新说明: \n${init_change_log}") 2229 | 2230 | 按任意键开始更新, 或者 Ctrl+C 取消 2231 | EOF 2232 | any_key_to_continue 2233 | echo "正在自动更新启动脚本..." 2234 | downlod_init_script 2235 | [ "$OS" = "CentOS" -a $OS_VSRSION -eq 7 ] && systemctl daemon-reload 2236 | 2237 | sed -i "s/^INIT_VERSION=${INIT_VERSION}/INIT_VERSION=${new_init_version}/" "$shell_path" 2238 | cat >&2 <<-EOF 2239 | 2240 | 服务启动脚本已更新到 v${new_init_version}, 可能需要重启服务器才能生效! 2241 | EOF 2242 | else 2243 | cat >&2 <<-'EOF' 2244 | 2245 | 未发现服务启动脚本更新... 2246 | EOF 2247 | fi 2248 | 2249 | cat >&2 <<-'EOF' 2250 | 2251 | 正在更新 Supervisor... 2252 | EOF 2253 | 2254 | easy_install -U supervisor >/dev/null 2>&1 2255 | 2256 | cat >&2 <<-'EOF' 2257 | 2258 | 更新操作已完成! 2259 | EOF 2260 | } 2261 | 2262 | # 卸载 Kcptun 2263 | uninstall_kcptun() { 2264 | permission_check 2265 | linux_check 2266 | cat >&2 <<-'EOF' 2267 | 2268 | 你选择了卸载 Kcptun 服务端 2269 | 按任意键继续...或者 Ctrl+C 取消 2270 | EOF 2271 | any_key_to_continue 2272 | echo "正在卸载 Kcptun 服务端并停止 Supervisor..." 2273 | service supervisord stop 2274 | 2275 | if [ "$OS" = "CentOS" ]; then 2276 | if yum list installed | grep -q "^jq\."; then 2277 | yum remove -y jq 2278 | fi 2279 | else 2280 | if dpkg -l | grep -q "\sjq\s"; then 2281 | apt-get remove --purge -y jq 2282 | fi 2283 | fi 2284 | 2285 | rm -f "$JQ" 2286 | rm -f "/etc/supervisor/conf.d/kcptun*.conf" 2287 | rm -rf "$KCPTUN_INSTALL_DIR" 2288 | rm -rf "$KCPTUN_LOG_DIR" 2289 | 2290 | cat >&2 <<-'EOF' 2291 | 2292 | 是否同时卸载 Supervisor ? 2293 | 注意: Supervisor 的配置文件将同时被删除 2294 | EOF 2295 | while : 2296 | do 2297 | read -p "(默认: 不卸载) 请选择 [y/n]: " yn 2298 | [ -z "$yn" ] && yn="n" 2299 | case ${yn:0:1} in 2300 | y|Y) 2301 | ;; 2302 | n|N) 2303 | break 2304 | ;; 2305 | *) 2306 | echo "输入有误, 请重新输入!" 2307 | continue 2308 | ;; 2309 | esac 2310 | 2311 | if [ "$OS" = "CentOS" ]; then 2312 | chkconfig supervisord off 2313 | else 2314 | update-rc.d -f supervisord remove 2315 | fi 2316 | 2317 | rm -rf "$(easy_install -mxN supervisor | grep 'Using.*supervisor.*\.egg' | awk '{print $2}')" 2318 | 2319 | rm -f /usr/local/bin/echo_supervisord_conf 2320 | rm -f /usr/local/bin/pidproxy 2321 | rm -f /usr/local/bin/supervisorctl 2322 | rm -f /usr/local/bin/supervisord 2323 | rm -rf /etc/supervisor/ 2324 | rm -rf /etc/init.d/supervisord 2325 | break 2326 | done 2327 | 2328 | cat >&2 <<-EOF 2329 | 2330 | Kcptun 服务端卸载完成, 欢迎再次使用。 2331 | 注意: 脚本没有自动卸载 python-setuptools (包含 easy_install) 2332 | 如有需要, 你可以使用: 2333 | 2334 | $([ "${OS}" = "CentOS" ] && echo -n "yum remove python-setuptools" || echo -n "apt-get remove --purge python-setuptools") 2335 | 2336 | 来手动卸载 2337 | EOF 2338 | } 2339 | 2340 | # 重启 Supervisor 2341 | restart_supervisor() { 2342 | if [ -x /etc/init.d/supervisord ]; then 2343 | 2344 | if [ -d "$KCPTUN_LOG_DIR" ]; then 2345 | rm -f "$KCPTUN_LOG_DIR"/* 2346 | else 2347 | mkdir -p "$KCPTUN_LOG_DIR" 2348 | fi 2349 | 2350 | if ! service supervisord restart; then 2351 | cat >&2 <<-'EOF' 2352 | 2353 | 重启 Supervisor 失败, Kcptun 无法正常启动! 2354 | EOF 2355 | 2356 | exit_with_error 2357 | fi 2358 | else 2359 | cat >&2 <<-'EOF' 2360 | 2361 | 未找到 Supervisor 服务, 请手动检查! 2362 | EOF 2363 | 2364 | exit_with_error 2365 | fi 2366 | 2367 | 2368 | } 2369 | 2370 | # 重新配置 2371 | reconfig_instance() { 2372 | permission_check 2373 | linux_check 2374 | 2375 | if [ -n "$1" ]; then 2376 | if is_number $1; then 2377 | if [ $1 -ne 1 ]; then 2378 | current_id="$1" 2379 | fi 2380 | else 2381 | cat >&2 <<-EOF 2382 | 2383 | 参数有误, 请使用 $0 reconfig 2384 | 为实例ID, 当前共有 $(get_instance_count) 个实例 2385 | EOF 2386 | 2387 | exit 1 2388 | fi 2389 | fi 2390 | 2391 | cat >&2 <<-EOF 2392 | 2393 | 你选择了重新配置实例 kcptun${current_id}, 正在开始操作... 2394 | EOF 2395 | 2396 | if [ ! -f "$(get_current_supervisor_config_file)" ]; then 2397 | cat >&2 <<-EOF 2398 | 2399 | 你选择的实例 kcptun${current_id} 不存在! 2400 | EOF 2401 | exit 1 2402 | fi 2403 | 2404 | get_arch 2405 | get_server_ip 2406 | 2407 | while : 2408 | do 2409 | cat >&2 <<-'EOF' 2410 | 2411 | 请选择操作: 2412 | (1) 重新配置实例所有选项 2413 | (2) 直接修改实例配置文件 2414 | EOF 2415 | read -p "(默认: 1) 请选择: " sel 2416 | echo 2417 | if [ -n "$sel" ]; then 2418 | case ${sel:0:1} in 2419 | 1) 2420 | ;; 2421 | 2) 2422 | echo "正在打开配置文件, 请手动修改..." 2423 | local config_file="$(get_current_config_file)" 2424 | 2425 | if [ -f "$config_file" ]; then 2426 | if command_exists vim; then 2427 | vim "$config_file" 2428 | load_instance_config 2429 | break 2430 | elif command_exists vi; then 2431 | vi "$config_file" 2432 | load_instance_config 2433 | break 2434 | elif command_exists gedit; then 2435 | gedit "$config_file" 2436 | load_instance_config 2437 | break 2438 | else 2439 | echo "未找到可用的编辑器, 正在进入全新配置..." 2440 | fi 2441 | else 2442 | echo "配置文件不存在, 正在进入全新配置..." 2443 | fi 2444 | ;; 2445 | *) 2446 | echo "输入有误, 请重新输入!" 2447 | continue 2448 | ;; 2449 | esac 2450 | fi 2451 | 2452 | set_kcptun_config 2453 | config_kcptun 2454 | config_firewall 2455 | break 2456 | done 2457 | 2458 | restart_supervisor 2459 | 2460 | cat >&2 <<-'EOF' 2461 | 2462 | 恭喜, Kcptun 服务端配置已更新! 2463 | EOF 2464 | get_installed_version 2465 | generate_mobile_args 2466 | show_config_info 2467 | show_installed_version 2468 | show_recommend_config 2469 | } 2470 | 2471 | usage() { 2472 | cat >&2 <<-EOF 2473 | 2474 | 请使用: $0