From 29feb6278da9c25c0815af02d2989c271aeca30c Mon Sep 17 00:00:00 2001 From: root Date: Sun, 2 Jun 2024 05:37:45 +0000 Subject: [PATCH] overtls-install-selfsign.sh script --- install/overtls-install-selfsign.sh | 771 ++++++++++++++++++++++++++++ 1 file changed, 771 insertions(+) create mode 100755 install/overtls-install-selfsign.sh diff --git a/install/overtls-install-selfsign.sh b/install/overtls-install-selfsign.sh new file mode 100755 index 0000000..d9485be --- /dev/null +++ b/install/overtls-install-selfsign.sh @@ -0,0 +1,771 @@ +#!/bin/bash + +#========================================================== +# System Request: Debian 7+ / Ubuntu 14.04+ / Centos 7+ +# Author: ssrlive +# Description: overTLS onekey for musl building and self-signature +# Version: 1.0.0 +#========================================================== + +#fonts color +Green="\033[32m" +Red="\033[31m" +Yellow="\033[33m" +GreenBG="\033[42;37m" +RedBG="\033[41;37m" +Font="\033[0m" + +#notification information +Info="${Green}[Info]${Font}" +OK="${Green}[OK]${Font}" +Error="${Red}[Error]${Font}" + +cur_dir=`pwd` + +function get_binary_target() { + local _binary_target="" + local CPU_ARCH=`uname -m` + case ${CPU_ARCH} in + x86_64) + _binary_target="x86_64-unknown-linux-musl" + ;; + aarch64) + _binary_target="aarch64-unknown-linux-musl" + ;; + armv7l) + _binary_target="armv7-unknown-linux-musleabihf" + ;; + *) + echo -e "${Error} ${RedBG} The current CPU architecture ${CPU_ARCH} is not supported. Please contact the author! ${Font}" + exit 1 + ;; + esac + echo ${_binary_target} +} + +cpu_arch_target=$(get_binary_target) + +overtls_install_sh="overtls-install-selfsign.sh" +overtls_install_sh_url="https://raw.githubusercontent.com/shadowsocksr-live/overtls/master/install/overtls-install-selfsign.sh" + +overtls_bin_url="https://github.com/shadowsocksr-live/overtls/releases/latest/download/overtls-${cpu_arch_target}.zip" +overtls_bin_zip_file="overtls-${cpu_arch_target}.zip" + +daemon_script_url="https://raw.githubusercontent.com/shadowsocksr-live/overtls/master/install/overtls-daemon.sh" +daemon_script_file="overtls-daemon.sh" +service_dir=/lib/systemd/system +service_name=overtls +service_stub=/etc/init.d/${service_name} + +config_file_path="/etc/overtls/config.json" +nginx_conf_dir="/etc/nginx/conf.d" +nginx_conf_file="${nginx_conf_dir}/overtls.conf" +site_dir="/fakesite" +site_cert_dir="/fakesite_cert" +target_bin_path="/usr/local/bin/overtls" +bin_name=overtls + +INSTALL_CMD="apt" + +export web_svr_domain="" +export web_svr_local_ip_addr="" +export web_svr_listen_port="443" +export web_svr_reverse_proxy_host="127.0.0.1" +export web_svr_reverse_proxy_port=10000 + +function random_string_gen() { + local PASS="" + local MATRIX="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" # "~!@#$%^&*()_+=" + local LENGTH=$1 + [ -z $1 ] && LENGTH="16" + while [ "${n:=1}" -le "$LENGTH" ] + do + PASS="$PASS${MATRIX:$(($RANDOM%${#MATRIX})):1}" + let n+=1 + done + + echo ${PASS} +} + +# Reverse proxy entry point. +export reverse_proxy_location=$(random_string_gen 20) + +function check_root_account() { + if [ `id -u` == 0 ]; then + echo -e "${OK} ${GreenBG} Current account is the root user, enter the installation process ${Font} " + sleep 3 + else + echo -e "${Error} ${RedBG} Current account is not root user, please switch to the root user and re-execute this script ${Font}" + exit 1 + fi +} + +source /etc/os-release + +# Extract the English name of the distribution system from VERSION, in order to add the corresponding nginx apt source under debian / ubuntu +VERSION=`echo ${VERSION} | awk -F "[()]" '{print $2}'` + +function check_system() { + if [[ "${ID}" == "centos" && ${VERSION_ID} -ge 7 ]]; then + echo -e "${OK} ${GreenBG} Current system is Centos ${VERSION_ID} ${VERSION} ${Font} " + INSTALL_CMD="yum" + echo -e "${OK} ${GreenBG} Please wait patiently during SElinux settings, do not perform other operations ${Font} " + setsebool -P httpd_can_network_connect 1 + echo -e "${OK} ${GreenBG} SElinux setup complete ${Font} " + ## Centos can also be installed by adding epel repositories, no changes are made currently + cat>/etc/yum.repos.d/nginx.repo<> /etc/apt/sources.list + echo "deb-src http://nginx.org/packages/mainline/debian/ ${VERSION} nginx" >> /etc/apt/sources.list + wget -nc https://nginx.org/keys/nginx_signing.key + apt-key add nginx_signing.key + fi + elif [[ "${ID}" == "ubuntu" && `echo "${VERSION_ID}" | cut -d '.' -f1` -ge 16 ]]; then + echo -e "${OK} ${GreenBG} Current system is Ubuntu ${VERSION_ID} ${VERSION_CODENAME} ${Font} " + INSTALL_CMD="apt" + ## Add nginx apt source + if [ ! -f nginx_signing.key ]; then + echo "deb http://nginx.org/packages/mainline/ubuntu/ ${VERSION_CODENAME} nginx" >> /etc/apt/sources.list + echo "deb-src http://nginx.org/packages/mainline/ubuntu/ ${VERSION_CODENAME} nginx" >> /etc/apt/sources.list + wget -nc https://nginx.org/keys/nginx_signing.key + apt-key add nginx_signing.key + fi + elif [[ "${ID}" == "linuxmint" ]]; then + INSTALL_CMD="apt" + else + echo -e "${Error} ${RedBG} Current system is ${ID} ${VERSION_ID} is not in the list of supported systems, installation is interrupted ${Font} " + exit 1 + fi +} + +function script_file_full_path() { + echo $(readlink -f "$0") +} + +function judge() { + if [[ $? -eq 0 ]]; then + echo -e "${OK} ${GreenBG} $1 Completed ${Font}" + sleep 1 + else + echo -e "${Error} ${RedBG} $1 Failed ${Font}" + exit 1 + fi +} + +function dependency_install() { + ${INSTALL_CMD} install curl wget git lsof -y + + if [[ "${ID}" == "centos" ]]; then + ${INSTALL_CMD} -y install crontabs bc unzip + ${INSTALL_CMD} -y install qrencode libtool openssl openssl-devel + else + ${INSTALL_CMD} install cron bc unzip vim curl -y + ${INSTALL_CMD} update -y + ${INSTALL_CMD} install qrencode autoconf libtool openssl libssl-dev -y + if [[ "${ID}" == "ubuntu" && `echo "${VERSION_ID}" | cut -d '.' -f1` -ge 20 ]]; then + ${INSTALL_CMD} install inetutils-ping -y + fi + fi + judge "Installing crontab" +} + +function random_listen_port() { + local overtls_port=0 + while true; do + overtls_port=$(shuf -i 9000-19999 -n 1) + expr ${overtls_port} + 1 &>/dev/null + if [ $? -eq 0 ]; then + if [ ${overtls_port} -ge 1 ] && [ ${overtls_port} -le 65535 ] && [ ${overtls_port:0:1} != 0 ]; then + break + fi + fi + done + echo ${overtls_port} +} + +function check_file_exists() { + local file_path="${1}" + + if [[ -z "${file_path}" ]]; then + echo -e "${RedBG} Error: file path given is empty. ${Font}" + exit 1 + fi + + if [ ! -f "${file_path}" ]; then + echo -e "${RedBG} Error: ${file_path} not found. ${Font}" + exit 1 + fi +} + +function get_vps_valid_ip() { + local web_svr_local_ip_v4_addr=`curl -4 ip.sb` + local web_svr_local_ip_v6_addr=`curl -6 ip.sb` + local ip_v4_regex='^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$' + local ip_v6_regex='^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$' + if [[ $web_svr_local_ip_v4_addr =~ $ip_v4_regex ]]; then + echo -e "${web_svr_local_ip_v4_addr}" + return 0 + elif [[ $web_svr_local_ip_v6_addr =~ $ip_v6_regex ]]; then + echo -e "${web_svr_local_ip_v6_addr}" + return 0 + else + echo "No valid IP found." + return 1 + fi +} + +function nginx_install() { + if [[ -x /usr/sbin/nginx ]] && [[ -d /etc/nginx ]]; then + echo -e "${OK} ${GreenBG} nginx has been installed before this moment ${Font}" + return 0 + fi + + if [[ "${ID}" == "ubuntu" ]]; then + ${INSTALL_CMD} install nginx-extras -y + else + ${INSTALL_CMD} install nginx -y + fi + + if [[ -d /etc/nginx ]]; then + echo -e "${OK} ${GreenBG} nginx installation is complete ${Font}" + sleep 2 + else + echo -e "${Error} ${RedBG} nginx installation failed ${Font}" + exit 5 + fi + + systemctl enable nginx + + if [[ ! -f /etc/nginx/nginx.conf.bak ]]; then + cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak + echo -e "${OK} ${GreenBG} nginx initial configuration backup completed ${Font}" + sleep 1 + fi +} + +function nginx_web_server_config_begin() { + rm -rf /etc/nginx/sites-enabled/* + + rm -rf ${site_dir} + mkdir -p ${site_dir}/.well-known/acme-challenge/ + chown -R www-data:www-data ${site_dir} + chmod -R 777 ${site_dir} + curl -L https://raw.githubusercontent.com/nginx/nginx/master/docs/html/index.html -o ${site_dir}/index.html + curl -L https://raw.githubusercontent.com/nginx/nginx/master/docs/html/50x.html -o ${site_dir}/50x.html + judge "[nginx] copy files" + + rm -rf ${nginx_conf_dir}/* + cat > ${nginx_conf_file} < account.key + judge "[CA] Create account key" + + local openssl_cnf="/etc/ssl/openssl.cnf" + if [[ "${ID}" == "centos" ]]; then + openssl_cnf="/etc/pki/tls/openssl.cnf" + fi + + openssl genrsa 4096 > private_key.pem + openssl req -new -sha256 -key private_key.pem -subj "/" -reqexts SAN -config <(cat ${openssl_cnf} <(printf "[SAN]\nsubjectAltName=DNS:${web_svr_domain}")) > domain.csr + judge "[CA] Create CSR file" + + curl -L https://raw.githubusercontent.com/diafygi/acme-tiny/master/acme_tiny.py -o acme_tiny.py + python3 acme_tiny.py --account-key ./account.key --csr ./domain.csr --acme-dir ${site_dir}/.well-known/acme-challenge/ > ./signed.crt + judge "[CA] Obtain website certificate" + + wget -O - https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem > intermediate.pem + cat signed.crt intermediate.pem > chained_cert.pem + judge "[CA] Merger of intermediate certificate and website certificate" + + wget -O - https://letsencrypt.org/certs/isrgrootx1.pem > root.pem + cat intermediate.pem root.pem > full_chained_cert.pem + judge "[CA] Root certificate and intermediate certificate merge" + + cd ${org_pwd} + + judge "[CA] Certificate configuration" +} + +function acme_cron_update(){ + cat > ${site_cert_dir}/renew_cert.sh < ./signed.crt || exit +wget -O - https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem > intermediate.pem +cat signed.crt intermediate.pem > chained_cert.pem +systemctl stop nginx +sleep 2 +systemctl start nginx +sleep 2 +EOF + + chmod a+x ${site_cert_dir}/renew_cert.sh + + local cron_name="cron" + if [[ "${ID}" == "centos" ]]; then + cron_name="crond" + fi + + systemctl stop ${cron_name} + sleep 2 + rm -rf tmp_info + crontab -l > tmp_info + echo "0 0 10 * * ${site_cert_dir}/renew_cert.sh >/dev/null 2>&1" >> tmp_info && crontab tmp_info && rm -rf tmp_info + systemctl start ${cron_name} + + judge "cron scheduled task update" +} + +function nginx_web_server_config_end() { + rm -rf ${nginx_conf_file} + cat > ${nginx_conf_file} </dev/null 2>&1 + if [ $? -ne 0 ]; then echo "wget failed"; exit -1; fi + + rm -rf ${bin_name} + unzip ${overtls_bin_zip_file} ${bin_name} >/dev/null 2>&1 + if [ $? -ne 0 ]; then echo "unzip failed"; exit -1; fi + + chmod +x ${bin_name} + rm -rf ${overtls_bin_zip_file} + + rm -rf ${local_bin_path} + local target_dir="$(dirname "${local_bin_path}")" + mv ${bin_name} ${target_dir} + + echo "${local_bin_path}" +} + +function write_overtls_config_file() { + local local_cfg_file_path="${1}" + local dir_path="$(dirname "${local_cfg_file_path}")" + mkdir -p "${dir_path}" + rm -rf "${local_cfg_file_path}" + + local hostname=$(echo $HOSTNAME) + local identity=$(random_string_gen 4) + + cat > ${local_cfg_file_path} < /dev/null 2>&1 + # if [ $? -eq 0 ]; then + # ${service_stub} stop + # fi + + # if [[ "${ID}" == "ubuntu" || "${ID}" == "debian" || "${ID}" == "linuxmint" ]]; then + # update-rc.d -f ${service_name} remove + # elif [[ "${ID}" == "centos" ]]; then + # chkconfig --del ${service_name} + # fi + + sleep 2 + + systemctl stop ${service_name}.service + sleep 2 + + systemctl disable ${service_name}.service + + rm -rf ${config_file_path} + rm -rf ${service_stub} + rm -rf ${target_bin_path} + rm -rf ${service_dir}/${service_name}.service + + systemctl daemon-reload + + echo "${service_name} uninstall success!" +} + +function install_binary_as_systemd_service() { + local role="${1}" + local local_bin_file_path=${2} + local local_cfg_file_path=${3} + + check_install_systemd_svc_params "${role}" "${local_bin_file_path}" "${local_cfg_file_path}" + + check_system + + if systemctl is-active --quiet ${service_name} ; then + echo "${service_name} is running" + echo -e "${Error} ${RedBG} Do you want to remove ${service_name} really and install a new one? (Y/N) ${Font}" && read action + case ${action} in + [yY][eE][sS]|[yY]) + echo -e "${GreenBG} Continue to install ${Font}" + sleep 2 + ;; + *) + echo -e "${RedBG} Installation terminated ${Font}" + exit 2 + ;; + esac + fi + + do_uninstall_service_action + + create_overtls_systemd_service "${role}" "${local_bin_file_path}" "${local_cfg_file_path}" +} + +function macos_install_binary_as_service() { + local role="${1}" + local local_bin_file_path=${2} + local local_cfg_file_path=${3} + local svc_daemon_file_path="~/Library/LaunchAgents/${service_name}.plist" + + cat > ${svc_daemon_file_path} < + + + + Label + ${service_name} + RunAtLoad + + KeepAlive + + StartInterval + 3 + ProgramArguments + + ${local_bin_file_path} + -r + ${role} + -c + ${local_cfg_file_path} + -d + + WorkingDirectory + /usr/local + + +EOF + + launchctl load ${svc_daemon_file_path} + launchctl start ${service_name} +} + +# Uninstall overtls +function uninstall_overtls() { + printf "Are you sure uninstall ${service_name}? (y/n)\n" + read -p "(Default: n):" answer + [ -z ${answer} ] && answer="n" + if [ "${answer}" == "y" ] || [ "${answer}" == "Y" ]; then + do_uninstall_service_action + else + echo + echo "uninstall cancelled, nothing to do..." + echo + fi +} + +function print_qrcode() { + local ot_exe_path="${1}" + local ot_cfg_path="${2}" + + check_file_exists "${ot_exe_path}" + check_file_exists "${ot_cfg_path}" + + local qrcode="$( ${ot_exe_path} -q -c ${ot_cfg_path} )" + echo "${qrcode}" + qrencode -t UTF8 "${qrcode}" | cat +} + +function install_overtls_remote_server() { + check_system + dependency_install + + web_svr_reverse_proxy_port=`random_listen_port` + + local ip_addr=$(get_vps_valid_ip) + local exit_status=$? + if [[ $exit_status -ne 0 ]]; then + echo "No valid IP found." + exit 1 + fi + + do_uninstall_service_action + + nginx_install + nginx_web_server_config_begin + do_lets_encrypt_certificate_authority + acme_cron_update + nginx_web_server_config_end + + local svc_bin_path=$(download_n_install_overtls_server_bin) + local cfg_path=$(write_overtls_config_file "${config_file_path}") + + if [ -f "${svc_bin_path}" ]; then + create_overtls_systemd_service "server" "${svc_bin_path}" "${cfg_path}" + else + echo "${service_name} install failed, please contact the author!" + exit 1 + fi + + echo + echo "======== config.json ========" + echo + cat ${cfg_path} + echo + echo "=============================" + echo + + print_qrcode "${svc_bin_path}" "${cfg_path}" +} + +function main() { + echo + echo "####################################################################" + echo "# Script of Install ${service_name} Server" + echo "# Author: ssrlive" + echo "# Github: https://github.com/shadowsocksr-live/overtls" + echo "####################################################################" + echo + + local action=${1} + [ -z ${1} ] && action="install" + case "${action}" in + install) + check_root_account + install_overtls_remote_server + ;; + uninstall) + check_root_account + uninstall_overtls + ;; + service) + local role="${2}" + local customer_binary_path="$3" + local customer_cfg_file_path="$4" + check_install_systemd_svc_params "${role}" "${customer_binary_path}" "${customer_cfg_file_path}" + if [[ "$(uname)" == "Linux" ]]; then + check_root_account + install_binary_as_systemd_service "${role}" "${customer_binary_path}" "${customer_cfg_file_path}" + elif [[ "$(uname)" == "Darwin" ]]; then + macos_install_binary_as_service "${role}" "${customer_binary_path}" "${customer_cfg_file_path}" + else + echo -e "${RedBG} Unsupported operating system! ${Font}" + exit 1 + fi + ;; + qrcode) + local svc_bin_path="${2}" + local cfg_path="${3}" + if [[ "$(uname)" == "Darwin" ]]; then + if ! command -v qrencode &> /dev/null ; then + if ! command -v brew &> /dev/null ; then + echo -e "${Info} ${Yellow} Homebrew not found, please install it first! ${Font}" + exit 1 + fi + brew install qrencode >/dev/null 2>&1 + fi + elif [[ "$(uname)" == "Linux" ]]; then + check_system + sudo ${INSTALL_CMD} -y install qrencode >/dev/null 2>&1 + fi + print_qrcode "${svc_bin_path}" "${cfg_path}" + ;; + *) + echo "Arguments error! [${action}]" + echo "Usage: `basename $0` [install|uninstall]" + ;; + esac + + exit 0 +} + +main "$@" +