Linux 搭建 vps

# Linux 搭建 vps

Centos7.9

# 安装

执行网友编写的一套集成脚本、一键安装 shadowsocks-libev

一键脚本已集成TCP优化、自动开启Google BBR(限 4.9 或更高版本内核)、自动安装 shadowsocks-libev

如需升级内核参考 升级/更新 Centos 7 内核 (opens new window)

# bash <(wget --no-check-certificate -qO- https://down.vpsaff.net/linux/shadowsocks/centos-shadowsocks-libev.sh)

# 下载脚本
wget https://down.24kplus.com/linux/shadowsocks/centos-shadowsocks-libev.sh

# 执行脚本安装
chmod +x centos-shadowsocks-libev.sh && ./centos-shadowsocks-libev.sh

# 安装说明

1、 提示设置SS密码,输入自定义密码后按回车,也可以直接按回车使用默认密码

ss1

2、 接下来选择SS要使用的服务器端口,输入自己喜欢的端口, 也可以直接按回车使用默认端口

ss2

3、 然后选择加密方式(仅保留相对安全的加密方式),如果选择chacha20的话,就输入对应序号3,按回车继续

ss3

4、 安装完成后,会有如下图安装成功的提示,记住各项信息,在客户端连接时需要用到

ss3

SS服务端安装成功后,就可以在电脑、手机、路由器等设备上的SS客户端上,按照以上设置的各项参数进行连接了。

# vps 网络优化

优化 CentOS 7 或者 Ubuntu 16.04 以上版本下的 shadowsocks-libev 网络速度,让 shadowsocks-libev 轻松跑满宽带。

# 一、优化吞吐量

1、编辑配置文件内容

sudo vi /etc/sysctl.d/local.conf

在文件最后添加一行

#max open files
fs.file-max = 51200
#max read buffer
net.core.rmem_max = 67108864
#max write buffer
net.core.wmem_max = 67108864
#default read buffer
net.core.rmem_default = 65536
#default write buffer
net.core.wmem_default = 65536
#max processor input queue
net.core.netdev_max_backlog = 4096
#max backlog
net.core.somaxconn = 4096
#resist SYN flood attacks
net.ipv4.tcp_syncookies = 1
#reuse timewait sockets when safe
net.ipv4.tcp_tw_reuse = 1
#turn off fast timewait sockets recycling
net.ipv4.tcp_tw_recycle = 0
#short FIN timeout
net.ipv4.tcp_fin_timeout = 30
#short keepalive time
net.ipv4.tcp_keepalive_time = 1200
#outbound port range
net.ipv4.ip_local_port_range = 10000 65000
#max SYN backlog
net.ipv4.tcp_max_syn_backlog = 4096
#max timewait sockets held by system simultaneously
net.ipv4.tcp_max_tw_buckets = 5000
#turn on TCP Fast Open on both client and server side
net.ipv4.tcp_fastopen = 3
#TCP receive buffer
net.ipv4.tcp_rmem = 4096 87380 67108864
#TCP write buffer
net.ipv4.tcp_wmem = 4096 65536 67108864
#turn on path MTU discovery
net.ipv4.tcp_mtu_probing = 1

net.ipv4.tcp_congestion_control = bbr # 增加

2、运行

sysctl --system

3、编辑配置文件 limits.conf

sudo vi /etc/security/limits.conf

在文件最后添加

* soft nofile 51200
* hard nofile 51200

4、编辑 shadowsocks-libev 服务

# 服务配置文件 (找自己的配置文件)
sudo vi /etc/systemd/system/shadowsocks-libev.service

在[Service]之后加入 ExecStartPre=/bin/sh -c ‘ulimit -n 51200’

[Unit]
Description=Shadowsocks-libev Server
After=network.target

[Service]
Type=simple
# 服务配置可能有所不一样,视实际而定
# 在这里加入 ExecStartPre=/bin/sh -c 'ulimit -n 51200'
ExecStartPre=/bin/sh -c 'ulimit -n 51200'
ExecStart=/usr/local/bin/ss-server -c /etc/shadowsocks-libev/config.json -u
Restart=on-abort

[Install]
WantedBy=multi-user.target

5、重新加载 shadowsocks-libev 服务配置

sudo systemctl daemon-reload

6、重启 Shadowsocks-libev 服务

sudo systemctl restart shadowsocks-libev

# 二、开启TCP Fast Open

TCP Fast Open可以降低Shadowsocks服务器和客户端的延迟。
实际上在上一步已经开启了TCP Fast Open,现在只需要在Shadowsocks配置中启用TCP Fast Open。

1、编辑config.json:

sudo vi /etc/shadowsocks-libev/config.json

将 fast_open 的值由 false 修改为 true

{
	"server":"0.0.0.0",
	"server_port":8388,
	"local_port":1080,
	"password":"password",
	"timeout":600,
	"method":"aes-256-cfb",
	// 这里设置 fast_open:true,如果没有则加入
	"fast_open": true
} 

2、重启 shadowsocks-libev 服务:

sudo systemctl restart shadowsocks-libev

# 三、开启 Google BBR

Google 开源了其 TCP BBR 拥塞控制算法,并提交到了 Linux 内核,从 4.9 开始,Linux 内核已经用上了该算法。根据以往的传统,Google 总是先在自家的生产环境上线运用后,才会将代码开源,此次也不例外。 根据实地测试,在部署了最新版内核并开启了 TCP BBR 的机器上,网速甚至可以提升好几个数量级。

1、查看BBR是否已经载入了系统模块

lsmod | grep bbr

2、如果结果中没有tcp_bbr,则先运行:

1. 查看linux内核版本 大于7.3即可
cat /etc/redhat-release

2. 执行一键安装脚本
wget --no-check-certificate https://github.com/teddysun/across/raw/master/bbr.sh && chmod +x bbr.sh && ./bbr.sh

3. 脚本执行完成会提示是否重启,输入 y 即可重启

3、检测是否安装完成:

# 1. 验证当前的TCP算法
sysctl net.ipv4.tcp_available_congestion_control
# 输出: net.ipv4.tcp_available_congestion_control = reno cubic bbr # 有 bbr 即可  


# 2. 查看BBR是否启动
sysctl net.ipv4.tcp_congestion_control
# 输出: net.ipv4.tcp_congestion_control = bbr 

# 3. 查看BBR是否已经载入了系统模块
lsmod | grep bbr
# 输出: tcp_bbr                20480  8 

优化到此基本完成。

# 客户端下载使用

shadowsocks windows 版本下载地址 (opens new window)

shadowsocks Android 版本下载地址 (opens new window)

# 参考

# 一键安装 ss-libev 脚本

See More
#!/usr/bin/env bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

red='\033[0;31m'
green='\033[0;32m'
yellow='\033[0;33m'
plain='\033[0m'

[[ $EUID -ne 0 ]] && echo -e "[${red}Error${plain}] This script must be run as root!" && exit 1

cur_dir=$( pwd )

libtool_file="libtool-2.4.6"
libtool_url="https://down.vpsaff.net/linux/libtool-2.4.6.tar.gz"

shadowsocks_libev_config="/etc/shadowsocks-libev/config.json"
shadowsocks_libev_service="/etc/systemd/system/shadowsocks-libev.service"

libsodium_file="libsodium-1.0.18-stable"
libsodium_url="https://down.vpsaff.net/linux/libsodium-1.0.18-stable.tar.gz"

mbedtls_file="mbedtls-2.16.6"
mbedtls_url="https://down.vpsaff.net/linux/mbedtls/mbedtls-2.16.6-gpl.tgz"

localconf_file="local"
localconf_url="https://down.vpsaff.net/linux/shadowsocks/local.conf"

common_ciphers=(
chacha20-ietf-poly1305
xchacha20-ietf-poly1305
aes-256-gcm
aes-192-gcm
aes-128-gcm
)

install_main(){
	check_sys
    install_prepare
    install_dependencies
	install_libtool
	install_mbedtls
	install_libsodium
	check_bbr_status
	if [ $? -eq 0 ]; then
		check_kernel_version
		if [ $? -eq 1 ]; then
			enable_bbr
		fi
	fi
	optimization_sys_config
    install_shadowsocks_libev
	install_completed_libev
    config_firewall
    install_cleanup
}

getversion(){
	grep -oE "[0-9.]+" /etc/redhat-release
}

check_sys(){
	if [ -f /etc/redhat-release ]; then
		echo ""
	else 
		echo "Only supported CentOS 7/8."
		exit 1
	fi
	local version="$(getversion)"
    sys_main_ver=${version%%.*}
	if [ "$sys_main_ver" != '7' ] && [ "$sys_main_ver" != '8' ]; then
		echo "Only supports CentOS 7/8."
		exit 1
	fi
}

check_kernel_version(){
	kernel_version=$(uname -r | awk -F'.' '{print $1}')
	kernel_main_version=$(uname -r | awk -F'.' '{print $2}')
	if [ $kernel_version -eq 4 ] && [ $kernel_main_version -lt 9 ]; then
		echo "Google BBR only supports kernel version 4.9 or higher"
		return 0
	elif [ $kernel_version -lt 4 ]; then
		echo "Google BBR only supports kernel version 4.9 or higher"
		return 0
	fi
	return 1
}

get_libev_ver(){
    libev_ver=$(wget --no-check-certificate -qO- https://api.github.com/repos/shadowsocks/shadowsocks-libev/releases/latest | grep 'tag_name' | cut -d\" -f4)
    [ -z ${libev_ver} ] && echo -e "[${red}Error${plain}] Get shadowsocks-libev latest version failed" && exit 1
}

download_shadowsocks_libev(){
    cd ${cur_dir}

    get_libev_ver
    shadowsocks_libev_file="shadowsocks-libev-$(echo ${libev_ver} | sed -e 's/^[a-zA-Z]//g')"
    local shadowsocks_libev_url="https://github.com/shadowsocks/shadowsocks-libev/releases/download/${libev_ver}/${shadowsocks_libev_file}.tar.gz"

    download "${shadowsocks_libev_file}.tar.gz" "${shadowsocks_libev_url}"
}

download(){
    local filename=$(basename $1)
    if [ -f ${1} ]; then
        echo "${filename} [found]"
    else
        echo "${filename} not found, download now..."
        wget --no-check-certificate -c -t3 -T60 -O ${1} ${2}
        if [ $? -ne 0 ]; then
            echo -e "[${red}Error${plain}] Download ${filename} failed."
            exit 1
        fi
    fi
}
install_libtool(){
    if [ ! -f /usr/bin/libtool ] && [ ! -f /usr/local/bin/libtool ]; then
        cd ${cur_dir}
        download "${libtool_file}.tar.gz" "${libtool_url}"
        tar -zxf ${libtool_file}.tar.gz
        cd ${libtool_file}
        ./configure --prefix=/usr && make && make install && ldconfig
        if [ $? -ne 0 ]; then
            echo -e "[${red}Error${plain}] ${libtool_file} install failed."
            install_cleanup
            exit 1
        fi
    else
        echo -e "[${green}Info${plain}] libtool already installed."
    fi
}
install_libsodium(){
    if [ ! -f /usr/lib/libsodium.a ]; then
        cd ${cur_dir}
        download "${libsodium_file}.tar.gz" "${libsodium_url}"
        tar -zxf ${libsodium_file}.tar.gz
        cd libsodium-stable
        ./configure --prefix=/usr && make && make install && ldconfig
        if [ $? -ne 0 ]; then
            echo -e "[${red}Error${plain}] ${libsodium_file} install failed."
            install_cleanup
            exit 1
        fi
    else
        echo -e "[${green}Info${plain}] libsodium already installed."
    fi
}

install_mbedtls(){
    if [ ! -f /usr/lib/libmbedtls.a ] && [ ! -f /usr/bin/mbedtls_hello ] && [ ! -f /usr/local/bin/mbedtls_hello ]; then
        cd ${cur_dir}
        download "${mbedtls_file}-gpl.tgz" "${mbedtls_url}"
        tar -xf ${mbedtls_file}-gpl.tgz
        cd ${mbedtls_file}
        make && make DESTDIR=/usr install && ldconfig
        if [ $? -ne 0 ]; then
            echo -e "[${red}Error${plain}] ${mbedtls_file} install failed."
            install_cleanup
            exit 1
        fi
    else
        echo -e "[${green}Info${plain}] mbedtls already installed."
    fi
}

install_shadowsocks_libev(){
	download_shadowsocks_libev
    cd ${cur_dir}
    tar -zxf ${shadowsocks_libev_file}.tar.gz
    cd ${shadowsocks_libev_file}
    ./configure --disable-documentation && make && make install
    if [ $? -eq 0 ]; then
		config_shadowsocks_libev
        systemctl start shadowsocks-libev
		systemctl enable shadowsocks-libev
    else
        echo
        echo -e "[${red}Error${plain}] shadowsocks-libev install failed."
        install_cleanup
        exit 1
    fi
}

install_completed_libev(){
    clear
    echo
    echo -e "Congratulations, shadowsocks-libev server install completed!"
    echo -e "Your Server IP        : ${red} $(get_ip) ${plain}"
    echo -e "Your Server Port      : ${red} ${shadowsocksport} ${plain}"
    echo -e "Your Password         : ${red} ${shadowsockspwd} ${plain}"
    echo -e "Your Encryption Method: ${red} ${shadowsockscipher} ${plain}"
}

install_cleanup(){
    cd ${cur_dir}
    rm -rf libsodium-stable ${libsodium_file}.tar.gz
    rm -rf ${mbedtls_file} ${mbedtls_file}-gpl.tgz
    rm -rf ${libtool_file} ${libtool_file}.tar.gz
    rm -rf ${shadowsocks_libev_file} ${shadowsocks_libev_file}.tar.gz
}

check_kernel_headers(){
    if rpm -qa | grep -q headers-$(uname -r); then
		return 0
	else
		return 1
	fi
}


config_shadowsocks_libev(){	
	if [ ! -d "$(dirname ${shadowsocks_libev_config})" ]; then
		mkdir -p $(dirname ${shadowsocks_libev_config})
	fi

	cat > ${shadowsocks_libev_config}<<-EOF
	{
		"server":"0.0.0.0",
		"server_port":${shadowsocksport},
		"password":"${shadowsockspwd}",
		"timeout":600,
		"method":"${shadowsockscipher}",
		"fast_open":true,
		"mode":"tcp_only"
	}
	EOF
	
	cat > ${shadowsocks_libev_service}<<-EOF
	[Unit]
	Description=shadowsocks-libev server
	After=network.target

	[Service]
	Type=simple
	ExecStartPre=/bin/sh -c 'ulimit -n 51200'
	ExecStart=/usr/local/bin/ss-server -c /etc/shadowsocks-libev/config.json
	Restart=on-abort

	[Install]
	WantedBy=multi-user.target
	EOF
}


error_detect_depends(){
    local command=$1
    local depend=`echo "${command}" | awk '{print $4}'`
    echo -e "[${green}Info${plain}] Starting to install package ${depend}"
    ${command} > /dev/null 2>&1
    if [ $? -ne 0 ]; then
        echo -e "[${red}Error${plain}] Failed to install ${red}${depend}${plain}"
        exit 1
    fi
}

install_dependencies(){
	local gcc_path=$(command -v gcc)
    if [ "${gcc_path}" == "" ]; then
		error_detect_depends "yum -y install gcc"
	fi
    yum_depends=(
		gettext autoconf automake make pcre-devel asciidoc xmlto c-ares-devel libev-devel wget tar m4 perl
	)
	for depend in ${yum_depends[@]}; do
		error_detect_depends "yum -y install ${depend}"
	done
	
	if [ "$sys_main_ver" == '8' ]; then
		install_python2
	fi
}

install_python2(){
	if [ ! -f /usr/lib64/libpython2.7.so.1.0 ]; then
		error_detect_depends "yum -y install python2"
	fi
}

config_firewall(){
    systemctl status firewalld > /dev/null 2>&1
	if [ $? -eq 0 ]; then
		default_zone=$(firewall-cmd --get-default-zone)
		firewall-cmd --permanent --zone=${default_zone} --add-port=${shadowsocksport}/tcp
		firewall-cmd --permanent --zone=${default_zone} --add-port=${shadowsocksport}/udp
		firewall-cmd --reload
	else
		echo -e "[${yellow}Warning${plain}] firewalld looks like not running or not installed, please enable port ${shadowsocksport} manually if necessary."
	fi
}

install_prepare_port() {
    while true
    do
    dport=$(shuf -i 9000-19999 -n 1)
    echo -e "Please enter a port for shadowsocks-libev [1-65535]"
    read -p "(Default port: ${dport}):" shadowsocksport
    [ -z "${shadowsocksport}" ] && shadowsocksport=${dport}
    expr ${shadowsocksport} + 1 &>/dev/null
    if [ $? -eq 0 ]; then
        if [ ${shadowsocksport} -ge 1 ] && [ ${shadowsocksport} -le 65535 ] && [ ${shadowsocksport:0:1} != 0 ]; then
            echo
            echo "port = ${shadowsocksport}"
            echo
            break
        fi
    fi
    echo -e "[${red}Error${plain}] Please enter a correct number [1-65535]"
    done
}

install_prepare_password(){
	local mkpasswd_path=$(command -v mkpasswd)
    if [ "${mkpasswd_path}" == "" ]; then
		error_detect_depends "yum -y install expect"
	fi
	radompassword=$(mkpasswd -l 18 -d 2 -s 0)

    echo "Please enter password for shadowsocks-libev"
    read -p "(Default password: ${radompassword}):" shadowsockspwd
    [ -z "${shadowsockspwd}" ] && shadowsockspwd=${radompassword}
    echo
    echo "password = ${shadowsockspwd}"
    echo
}

install_prepare_cipher(){
    while true
    do
    echo -e "Please select stream cipher for shadowsocks-libev:"

	for ((i=1;i<=${#common_ciphers[@]};i++ )); do
		hint="${common_ciphers[$i-1]}"
		echo -e "${green}${i}${plain}) ${hint}"
	done
	read -p "Which cipher you'd select(Default: ${common_ciphers[0]}):" pick
	[ -z "$pick" ] && pick=1
	expr ${pick} + 1 &>/dev/null
	if [ $? -ne 0 ]; then
		echo -e "[${red}Error${plain}] Please enter a number"
		continue
	fi
	if [[ "$pick" -lt 1 || "$pick" -gt ${#common_ciphers[@]} ]]; then
		echo -e "[${red}Error${plain}] Please enter a number between 1 and ${#common_ciphers[@]}"
		continue
	fi
	shadowsockscipher=${common_ciphers[$pick-1]}
    
   

    echo
    echo "cipher = ${shadowsockscipher}"
    echo
    break
    done
}

check_bbr_status() {
    local param=$(lsmod | grep bbr | awk '{print $1}')
    if [[ "${param}" == "tcp_bbr" ]]; then
		echo "[${green}Info${plain}] Your Google BBR enabled"
        return 1
    else
        return 0
    fi
}

enable_bbr() {
	modprobe tcp_bbr
    echo "tcp_bbr" >> /etc/modules-load.d/modules.conf
    echo "net.core.default_qdisc = fq" >> /etc/sysctl.conf
    echo "net.ipv4.tcp_congestion_control = bbr" >> /etc/sysctl.conf
    sysctl -p
	echo "[${green}Info${plain}] Google BBR enabled"
}

optimization_sys_config(){
	cd ${cur_dir}
	if [ ! -f /etc/sysctl.d/local.conf ]; then
		download "${localconf_file}.conf" "${localconf_url}"
		mv ${localconf_file}.conf /etc/sysctl.d/local.conf
		sysctl --system	
	fi
	if [ "$(grep "* soft nofile" /etc/security/limits.conf)" == "" ]; then
		echo "* soft nofile 51200" >> /etc/security/limits.conf
	fi
	if [ "$(grep "* hard nofile" /etc/security/limits.conf)" == "" ]; then
		echo "* hard nofile 51200" >> /etc/security/limits.conf
	fi
}

get_ip(){
    local IP=$( ip addr | egrep -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | egrep -v "^192\.168|^172\.1[6-9]\.|^172\.2[0-9]\.|^172\.3[0-2]\.|^10\.|^127\.|^255\.|^0\." | head -n 1 )
    [ -z ${IP} ] && IP=$( wget -qO- -t1 -T2 api.24kplus.com/myip )
    echo ${IP}
}

get_char(){
    SAVEDSTTY=$(stty -g)
    stty -echo
    stty cbreak
    dd if=/dev/tty bs=1 count=1 2> /dev/null
    stty -raw
    stty echo
    stty $SAVEDSTTY
}

install_prepare(){

    install_prepare_password
    install_prepare_port
    install_prepare_cipher

    echo
    echo "Press any key to start...or Press Ctrl+C to cancel"
    char=`get_char`

}

install_main

脚本地址Github (opens new window)

参考文章 (opens new window)

# 一键安装 bbr 脚本

See More
#!/usr/bin/env bash
#
# Auto install latest kernel for TCP BBR
#
# System Required:  CentOS 6+, Debian8+, Ubuntu16+
#
# Copyright (C) 2016-2021 Teddysun <i@teddysun.com>
#
# URL: https://teddysun.com/489.html
#

cur_dir="$(cd -P -- "$(dirname -- "$0")" && pwd -P)"

_red() {
    printf '\033[1;31;31m%b\033[0m' "$1"
}

_green() {
    printf '\033[1;31;32m%b\033[0m' "$1"
}

_yellow() {
    printf '\033[1;31;33m%b\033[0m' "$1"
}

_info() {
    _green "[Info] "
    printf -- "%s" "$1"
    printf "\n"
}

_warn() {
    _yellow "[Warning] "
    printf -- "%s" "$1"
    printf "\n"
}

_error() {
    _red "[Error] "
    printf -- "%s" "$1"
    printf "\n"
    exit 1
}

_exists() {
    local cmd="$1"
    if eval type type > /dev/null 2>&1; then
        eval type "$cmd" > /dev/null 2>&1
    elif command > /dev/null 2>&1; then
        command -v "$cmd" > /dev/null 2>&1
    else
        which "$cmd" > /dev/null 2>&1
    fi
    local rt=$?
    return ${rt}
}

_os() {
    local os=""
    [ -f "/etc/debian_version" ] && source /etc/os-release && os="${ID}" && printf -- "%s" "${os}" && return
    [ -f "/etc/redhat-release" ] && os="centos" && printf -- "%s" "${os}" && return
}

_os_full() {
    [ -f /etc/redhat-release ] && awk '{print ($1,$3~/^[0-9]/?$3:$4)}' /etc/redhat-release && return
    [ -f /etc/os-release ] && awk -F'[= "]' '/PRETTY_NAME/{print $3,$4,$5}' /etc/os-release && return
    [ -f /etc/lsb-release ] && awk -F'[="]+' '/DESCRIPTION/{print $2}' /etc/lsb-release && return
}

_os_ver() {
    local main_ver="$( echo $(_os_full) | grep -oE  "[0-9.]+")"
    printf -- "%s" "${main_ver%%.*}"
}

_error_detect() {
    local cmd="$1"
    _info "${cmd}"
    eval ${cmd}
    if [ $? -ne 0 ]; then
        _error "Execution command (${cmd}) failed, please check it and try again."
    fi
}

_is_digit(){
    local input=${1}
    if [[ "$input" =~ ^[0-9]+$ ]]; then
        return 0
    else
        return 1
    fi
}

_is_64bit(){
    if [ $(getconf WORD_BIT) = '32' ] && [ $(getconf LONG_BIT) = '64' ]; then
        return 0
    else
        return 1
    fi
}

_version_ge(){
    test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" == "$1"
}

get_valid_valname(){
    local val=${1}
    local new_val=$(eval echo $val | sed 's/[-.]/_/g')
    echo ${new_val}
}

get_hint(){
    local val=${1}
    local new_val=$(get_valid_valname $val)
    eval echo "\$hint_${new_val}"
}

#Display Memu
display_menu(){
    local soft=${1}
    local default=${2}
    eval local arr=(\${${soft}_arr[@]})
    local default_prompt
    if [[ "$default" != "" ]]; then
        if [[ "$default" == "last" ]]; then
            default=${#arr[@]}
        fi
        default_prompt="(default ${arr[$default-1]})"
    fi
    local pick
    local hint
    local vname
    local prompt="which ${soft} you'd select ${default_prompt}: "

    while :
    do
        echo -e "\n------------ ${soft} setting ------------\n"
        for ((i=1;i<=${#arr[@]};i++ )); do
            vname="$(get_valid_valname ${arr[$i-1]})"
            hint="$(get_hint $vname)"
            [[ "$hint" == "" ]] && hint="${arr[$i-1]}"
            echo -e "${green}${i}${plain}) $hint"
        done
        echo
        read -p "${prompt}" pick
        if [[ "$pick" == "" && "$default" != "" ]]; then
            pick=${default}
            break
        fi

        if ! _is_digit "$pick"; then
            prompt="Input error, please input a number"
            continue
        fi

        if [[ "$pick" -lt 1 || "$pick" -gt ${#arr[@]} ]]; then
            prompt="Input error, please input a number between 1 and ${#arr[@]}: "
            continue
        fi

        break
    done

    eval ${soft}=${arr[$pick-1]}
    vname="$(get_valid_valname ${arr[$pick-1]})"
    hint="$(get_hint $vname)"
    [[ "$hint" == "" ]] && hint="${arr[$pick-1]}"
    echo -e "\nyour selection: $hint\n"
}

get_latest_version() {
    latest_version=($(wget -qO- https://kernel.ubuntu.com/~kernel-ppa/mainline/ | awk -F'\"v' '/v[4-9]./{print $2}' | cut -d/ -f1 | grep -v - | sort -V))
    [ ${#latest_version[@]} -eq 0 ] && _error "Get latest kernel version failed."
    kernel_arr=()
    for i in ${latest_version[@]}; do
        if _version_ge $i 5.9; then
            kernel_arr+=($i);
        fi
    done
    display_menu kernel last
    if _is_64bit; then
        deb_name=$(wget -qO- https://kernel.ubuntu.com/~kernel-ppa/mainline/v${kernel}/ | grep "linux-image" | grep "generic" | awk -F'\">' '/amd64.deb/{print $2}' | cut -d'<' -f1 | head -1)
        deb_kernel_url="https://kernel.ubuntu.com/~kernel-ppa/mainline/v${kernel}/${deb_name}"
        deb_kernel_name="linux-image-${kernel}-amd64.deb"
        modules_deb_name=$(wget -qO- https://kernel.ubuntu.com/~kernel-ppa/mainline/v${kernel}/ | grep "linux-modules" | grep "generic" | awk -F'\">' '/amd64.deb/{print $2}' | cut -d'<' -f1 | head -1)
        deb_kernel_modules_url="https://kernel.ubuntu.com/~kernel-ppa/mainline/v${kernel}/${modules_deb_name}"
        deb_kernel_modules_name="linux-modules-${kernel}-amd64.deb"
    else
        deb_name=$(wget -qO- https://kernel.ubuntu.com/~kernel-ppa/mainline/v${kernel}/ | grep "linux-image" | grep "generic" | awk -F'\">' '/i386.deb/{print $2}' | cut -d'<' -f1 | head -1)
        deb_kernel_url="https://kernel.ubuntu.com/~kernel-ppa/mainline/v${kernel}/${deb_name}"
        deb_kernel_name="linux-image-${kernel}-i386.deb"
        modules_deb_name=$(wget -qO- https://kernel.ubuntu.com/~kernel-ppa/mainline/v${kernel}/ | grep "linux-modules" | grep "generic" | awk -F'\">' '/i386.deb/{print $2}' | cut -d'<' -f1 | head -1)
        deb_kernel_modules_url="https://kernel.ubuntu.com/~kernel-ppa/mainline/v${kernel}/${modules_deb_name}"
        deb_kernel_modules_name="linux-modules-${kernel}-i386.deb"
    fi
    [ -z "${deb_name}" ] && _error "Getting Linux kernel binary package name failed, maybe kernel build failed. Please choose other one and try again."
}

get_char() {
    SAVEDSTTY=`stty -g`
    stty -echo
    stty cbreak
    dd if=/dev/tty bs=1 count=1 2> /dev/null
    stty -raw
    stty echo
    stty $SAVEDSTTY
}

check_bbr_status() {
    local param=$(sysctl net.ipv4.tcp_congestion_control | awk '{print $3}')
    if [[ x"${param}" == x"bbr" ]]; then
        return 0
    else
        return 1
    fi
}

check_kernel_version() {
    local kernel_version=$(uname -r | cut -d- -f1)
    if _version_ge ${kernel_version} 4.9; then
        return 0
    else
        return 1
    fi
}

# Check OS version
check_os() {
    if _exists "virt-what"; then
        virt="$(virt-what)"
    elif _exists "systemd-detect-virt"; then
        virt="$(systemd-detect-virt)"
    fi
    if [ -n "${virt}" -a "${virt}" = "lxc" ]; then
        _error "Virtualization method is LXC, which is not supported."
    fi
    if [ -n "${virt}" -a "${virt}" = "openvz" ] || [ -d "/proc/vz" ]; then
        _error "Virtualization method is OpenVZ, which is not supported."
    fi
    [ -z "$(_os)" ] && _error "Not supported OS"
    case "$(_os)" in
        ubuntu)
            [ -n "$(_os_ver)" -a "$(_os_ver)" -lt 16 ] && _error "Not supported OS, please change to Ubuntu 16+ and try again."
            ;;
        debian)
            [ -n "$(_os_ver)" -a "$(_os_ver)" -lt 8 ] &&  _error "Not supported OS, please change to Debian 8+ and try again."
            ;;
        centos)
            [ -n "$(_os_ver)" -a "$(_os_ver)" -lt 6 ] &&  _error "Not supported OS, please change to CentOS 6+ and try again."
            ;;
        *)
            _error "Not supported OS"
            ;;
    esac
}

sysctl_config() {
    sed -i '/net.core.default_qdisc/d' /etc/sysctl.conf
    sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf
    echo "net.core.default_qdisc = fq" >> /etc/sysctl.conf
    echo "net.ipv4.tcp_congestion_control = bbr" >> /etc/sysctl.conf
    sysctl -p >/dev/null 2>&1
}

install_kernel() {
    case "$(_os)" in
        centos)
            if [ -n "$(_os_ver)" ]; then
                if ! _exists "yum-config-manager"; then
                    _error_detect "yum install -y yum-utils"
                fi
                if [ "$(_os_ver)" -eq 6 ]; then
                    _error_detect "rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org"
                    rpm_kernel_url="https://dl.lamp.sh/files/"
                    if _is_64bit; then
                        rpm_kernel_name="kernel-ml-4.18.20-1.el6.elrepo.x86_64.rpm"
                        rpm_kernel_devel_name="kernel-ml-devel-4.18.20-1.el6.elrepo.x86_64.rpm"
                    else
                        rpm_kernel_name="kernel-ml-4.18.20-1.el6.elrepo.i686.rpm"
                        rpm_kernel_devel_name="kernel-ml-devel-4.18.20-1.el6.elrepo.i686.rpm"
                    fi
                    _error_detect "wget -c -t3 -T60 -O ${rpm_kernel_name} ${rpm_kernel_url}${rpm_kernel_name}"
                    _error_detect "wget -c -t3 -T60 -O ${rpm_kernel_devel_name} ${rpm_kernel_url}${rpm_kernel_devel_name}"
                    [ -s "${rpm_kernel_name}" ] && _error_detect "rpm -ivh ${rpm_kernel_name}" || _error "Download ${rpm_kernel_name} failed, please check it."
                    [ -s "${rpm_kernel_devel_name}" ] && _error_detect "rpm -ivh ${rpm_kernel_devel_name}" || _error "Download ${rpm_kernel_devel_name} failed, please check it."
                    rm -f ${rpm_kernel_name} ${rpm_kernel_devel_name}
                    [ ! -f "/boot/grub/grub.conf" ] && _error "/boot/grub/grub.conf not found, please check it."
                    sed -i 's/^default=.*/default=0/g' /boot/grub/grub.conf
                elif [ "$(_os_ver)" -eq 7 ]; then
                    _error_detect "yum -y install centos-release-xen-48"
                    [ x"$(yum-config-manager centos-virt-xen-48 | grep -w enabled | awk '{print $3}')" != x"True" ] && _error_detect "yum-config-manager --enable centos-virt-xen-48"
                    _error_detect "yum -y update kernel"
                    _error_detect "yum -y install kernel-devel"
                fi
            fi
            ;;
        ubuntu|debian)
            _info "Getting latest kernel version..."
            get_latest_version
            if [ -n "${modules_deb_name}" ]; then
                _error_detect "wget -c -t3 -T60 -O ${deb_kernel_modules_name} ${deb_kernel_modules_url}"
            fi
            _error_detect "wget -c -t3 -T60 -O ${deb_kernel_name} ${deb_kernel_url}"
            _error_detect "dpkg -i ${deb_kernel_modules_name} ${deb_kernel_name}"
            rm -f ${deb_kernel_modules_name} ${deb_kernel_name}
            _error_detect "/usr/sbin/update-grub"
            ;;
        *)
            ;; # do nothing
    esac
}

reboot_os() {
    echo
    _info "The system needs to reboot."
    read -p "Do you want to restart system? [y/n]" is_reboot
    if [[ ${is_reboot} == "y" || ${is_reboot} == "Y" ]]; then
        reboot
    else
        _info "Reboot has been canceled..."
        exit 0
    fi
}

install_bbr() {
    if check_bbr_status; then
        echo
        _info "TCP BBR has already been enabled. nothing to do..."
        exit 0
    fi
    if check_kernel_version; then
        echo
        _info "The kernel version is greater than 4.9, directly setting TCP BBR..."
        sysctl_config
        _info "Setting TCP BBR completed..."
        exit 0
    fi
    check_os
    install_kernel
    sysctl_config
    reboot_os
}

[[ $EUID -ne 0 ]] && _error "This script must be run as root"
opsy=$( _os_full )
arch=$( uname -m )
lbit=$( getconf LONG_BIT )
kern=$( uname -r )

clear
echo "---------- System Information ----------"
echo " OS      : $opsy"
echo " Arch    : $arch ($lbit Bit)"
echo " Kernel  : $kern"
echo "----------------------------------------"
echo " Automatically enable TCP BBR script"
echo
echo " URL: https://teddysun.com/489.html"
echo "----------------------------------------"
echo
echo "Press any key to start...or Press Ctrl+C to cancel"
char=$(get_char)

install_bbr 2>&1 | tee ${cur_dir}/install_bbr.log

脚本地址Github (opens new window)

# 参考文章

CentOS7安装TCP BBR加速 (opens new window)

升级/更新 Centos 7 内核 (opens new window)