362 lines
16 KiB (Stored with Git LFS)
Bash
362 lines
16 KiB (Stored with Git LFS)
Bash
#!/bin/bash
|
||
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$PATH
|
||
|
||
: '
|
||
Copyright (C) 2022 - now HaoZi Technology Co., Ltd.
|
||
|
||
This program is free software: you can redistribute it and/or modify
|
||
it under the terms of the GNU Affero General Public License as published
|
||
by the Free Software Foundation, either version 3 of the License, or
|
||
(at your option) any later version.
|
||
|
||
This program is distributed in the hope that it will be useful,
|
||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
GNU Affero General Public License for more details.
|
||
|
||
You should have received a copy of the GNU Affero General Public License
|
||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||
'
|
||
|
||
source <(curl -f -s --connect-timeout 10 --retry 3 https://dl.cdn.haozi.net/panel/public.sh)
|
||
if [ $? -ne 0 ]; then
|
||
echo "下载 public.sh 失败,请检查网络或稍后重试。"
|
||
echo "Download public.sh failed, please check the network or try again later."
|
||
exit 1
|
||
fi
|
||
|
||
LOGO="+----------------------------------------------------\n| 耗子面板安装脚本\n| Rat Panel install script\n+----------------------------------------------------\n| Copyright © 2022-"$(date +%Y)" 耗子科技 All rights reserved.\n+----------------------------------------------------"
|
||
current_path=$(pwd)
|
||
ssh_port=$(cat /etc/ssh/sshd_config | grep 'Port ' | awk '{print $2}')
|
||
in_china=$(curl --retry 2 -m 10 -L https://www.qualcomm.cn/cdn-cgi/trace 2>/dev/null | grep -qx 'loc=CN' && echo "true" || echo "false")
|
||
|
||
Prepare_System() {
|
||
if [ $(whoami) != "root" ]; then
|
||
error "请使用root用户运行安装命令(Please run the installation command using the root user)"
|
||
fi
|
||
|
||
if [ ${OS} == "unknown" ]; then
|
||
error "系统不支持安装面板(The system does not support installing the panel)"
|
||
fi
|
||
if [ ${ARCH} != "x86_64" ] && [ ${ARCH} != "aarch64" ]; then
|
||
error "系统架构不支持安装面板(The system architecture does not support installing the panel)"
|
||
fi
|
||
|
||
if [ ${ARCH} == "x86_64" ]; then
|
||
if [ "$(cat /proc/cpuinfo | grep -c ssse3)" -lt "1" ]; then
|
||
error "CPU至少需支持x86-64-v2指令集(CPU must support at least the x86-64-v2 instruction set)"
|
||
fi
|
||
fi
|
||
|
||
kernel_version=$(uname -r | awk -F '.' '{print $1}')
|
||
if [ "${kernel_version}" -lt "4" ]; then
|
||
error "系统内核版本太低,请升级到4.x以上版本(The system kernel version is too low, please upgrade to version 4.x or above)"
|
||
fi
|
||
|
||
is_64bit=$(getconf LONG_BIT)
|
||
if [ "${is_64bit}" != '64' ]; then
|
||
error "请更换64位系统安装面板(Please switch to a 64-bit system to install the panel)"
|
||
fi
|
||
|
||
if [ -f "${setup_path}/panel/web" ]; then
|
||
error "面板已安装,无需重复安装(Panel is already installed, no need to install again)"
|
||
fi
|
||
|
||
if ! id -u "www" >/dev/null 2>&1; then
|
||
groupadd www
|
||
useradd -s /sbin/nologin -g www www
|
||
fi
|
||
|
||
if [ ! -d ${setup_path} ]; then
|
||
mkdir ${setup_path}
|
||
fi
|
||
|
||
timedatectl set-timezone Asia/Shanghai
|
||
|
||
[ -s /etc/selinux/config ] && sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
|
||
setenforce 0 >/dev/null 2>&1
|
||
|
||
ulimit -n 1048576
|
||
echo 2147483584 >/proc/sys/fs/file-max
|
||
soft_nofile_check=$(cat /etc/security/limits.conf | grep '^* soft nofile .*$')
|
||
hard_nofile_check=$(cat /etc/security/limits.conf | grep '^* hard nofile .*$')
|
||
soft_nproc_check=$(cat /etc/security/limits.conf | grep '^* soft nproc .*$')
|
||
hard_nproc_check=$(cat /etc/security/limits.conf | grep '^* hard nproc .*$')
|
||
fs_file_max_check=$(cat /etc/sysctl.conf | grep '^fs.file-max.*$')
|
||
if [ "${soft_nofile_check}" == "" ]; then
|
||
echo "* soft nofile 1048576" >>/etc/security/limits.conf
|
||
fi
|
||
if [ "${hard_nofile_check}" == "" ]; then
|
||
echo "* hard nofile 1048576" >>/etc/security/limits.conf
|
||
fi
|
||
if [ "${soft_nproc_check}" == "" ]; then
|
||
echo "* soft nproc 1048576" >>/etc/security/limits.conf
|
||
fi
|
||
if [ "${hard_nproc_check}" == "" ]; then
|
||
echo "* hard nproc 1048576" >>/etc/security/limits.conf
|
||
fi
|
||
if [ "${fs_file_max_check}" == "" ]; then
|
||
echo fs.file-max = 2147483584 >>/etc/sysctl.conf
|
||
fi
|
||
|
||
# 自动开启 BBR
|
||
bbr_support_check=$(ls -l /lib/modules/*/kernel/net/ipv4 | grep -c tcp_bbr)
|
||
bbr_open_check=$(sysctl net.ipv4.tcp_congestion_control | grep -c bbr)
|
||
if [ "${bbr_support_check}" != "0" ] && [ "${bbr_open_check}" == "0" ]; then
|
||
qdisc=$(sysctl net.core.default_qdisc | awk '{print $3}')
|
||
echo "net.core.default_qdisc=${qdisc}" >>/etc/sysctl.conf
|
||
echo "net.ipv4.tcp_congestion_control=bbr" >>/etc/sysctl.conf
|
||
sysctl -p
|
||
fi
|
||
|
||
if [ ${OS} == "rhel" ]; then
|
||
if ${in_china}; then
|
||
sed -e 's|^mirrorlist=|#mirrorlist=|g' \
|
||
-e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.tencent.com/rocky|g' \
|
||
-e 's|^# baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.tencent.com/rocky|g' \
|
||
-i.bak \
|
||
/etc/yum.repos.d/[Rr]ocky*.repo >/dev/null 2>&1
|
||
sed -e 's|^mirrorlist=|#mirrorlist=|g' \
|
||
-e 's|^#baseurl=https://repo.almalinux.org|baseurl=https://mirrors.tencent.com|g' \
|
||
-e 's|^# baseurl=https://repo.almalinux.org|baseurl=https://mirrors.tencent.com|g' \
|
||
-i.bak \
|
||
/etc/yum.repos.d/[Aa]lmalinux*.repo >/dev/null 2>&1
|
||
sed -e 's|^mirrorlist=|#mirrorlist=|g' \
|
||
-e 's|^#baseurl=http://mirror.centos.org/$contentdir|baseurl=https://mirrors.tencent.com/centos-stream|g' \
|
||
-e 's|^# baseurl=http://mirror.centos.org/$contentdir|baseurl=https://mirrors.tencent.com/centos-stream|g' \
|
||
-i.bak \
|
||
/etc/yum.repos.d/[Cc]ent*.repo >/dev/null 2>&1
|
||
fi
|
||
dnf makecache -y
|
||
dnf install dnf-plugins-core -y
|
||
dnf config-manager --set-enabled epel
|
||
if ${in_china}; then
|
||
sed -i 's|^#baseurl=https://download.example/pub|baseurl=https://mirrors.tencent.com|' /etc/yum.repos.d/epel* >/dev/null 2>&1
|
||
sed -i 's|^# baseurl=https://download.example/pub|baseurl=https://mirrors.tencent.com|' /etc/yum.repos.d/epel* >/dev/null 2>&1
|
||
sed -i 's|^metalink|#metalink|' /etc/yum.repos.d/epel* >/dev/null 2>&1
|
||
dnf makecache -y
|
||
fi
|
||
# EL 9
|
||
dnf config-manager --set-enabled crb
|
||
dnf install epel-release epel-next-release -y
|
||
# 部分系统可能没有这两个包,需要手动安装
|
||
# 对于 openEuler 这种大改的系统,下载会 404,这没有影响
|
||
if [ "$?" != "0" ]; then
|
||
if ${in_china}; then
|
||
dnf install -y https://mirrors.tencent.com/epel/epel-release-latest-$(rpm -E %{rhel}).noarch.rpm
|
||
dnf install -y https://mirrors.tencent.com/epel/epel-next-release-latest-$(rpm -E %{rhel}).noarch.rpm
|
||
else
|
||
dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-$(rpm -E %{rhel}).noarch.rpm
|
||
dnf install -y https://dl.fedoraproject.org/pub/epel/epel-next-release-latest-$(rpm -E %{rhel}).noarch.rpm
|
||
fi
|
||
fi
|
||
# Rocky Linux
|
||
/usr/bin/crb enable >/dev/null 2>&1
|
||
# openEuler
|
||
if [ -f /etc/openEuler-release ]; then
|
||
# 清理旧配置
|
||
grep -rl '^baseurl=https://repo.oepkgs.net' /etc/yum.repos.d/ | xargs -I {} rm -f {}
|
||
dnf config-manager --add-repo https://repo.oepkgs.net/openeuler/rpm/$(awk '{print $1"-"$3"-"$4}' /etc/openEuler-release | sed 's/[()]//g')/extras/$(uname -m)/
|
||
oe_version=$(awk '{print $3}' /etc/openEuler-release | cut -d '.' -f 1)
|
||
case ${oe_version} in
|
||
22)
|
||
dnf config-manager --add-repo https://repo.oepkgs.net/openeuler/rpm/$(awk '{print $1"-"$3"-"$4}' /etc/openEuler-release | sed 's/[()]//g')/extras/$(uname -m)/
|
||
dnf config-manager --add-repo https://repo.oepkgs.net/openeuler/rpm/$(awk '{print $1"-"$3"-"$4}' /etc/openEuler-release | sed 's/[()]//g')/compatible/f33/$(uname -m)/
|
||
;;
|
||
24)
|
||
# openEuler 24 目前没有 p7zip-plugins,等他们自己修复
|
||
error "openEuler 24 暂不支持安装面板(Panel installation is not supported on openEuler 24)"
|
||
;;
|
||
*)
|
||
error "不支持的 openEuler 版本(Unsupported openEuler version)"
|
||
;;
|
||
esac
|
||
# 禁用gpcheck,这仓库缺签名
|
||
grep -rl '^baseurl=https://repo.oepkgs.net' /etc/yum.repos.d/ | xargs -I {} sh -c 'echo "gpgcheck=0" >> "{}"'
|
||
fi
|
||
dnf makecache -y
|
||
dnf install -y bash curl wget zip unzip tar p7zip p7zip-plugins git jq git-core dos2unix rsyslog make sudo
|
||
elif [ ${OS} == "debian" ] || [ ${OS} == "ubuntu" ]; then
|
||
if ${in_china}; then
|
||
# Debian
|
||
sed -i 's/deb.debian.org/mirrors.tencent.com/g' /etc/apt/sources.list >/dev/null 2>&1
|
||
sed -i 's/deb.debian.org/mirrors.tencent.com/g' /etc/apt/sources.list.d/debian.sources >/dev/null 2>&1
|
||
sed -i -e 's|security.debian.org/\? |security.debian.org/debian-security |g' \
|
||
-e 's|security.debian.org|mirrors.tencent.com|g' \
|
||
-e 's|deb.debian.org/debian-security|mirrors.tencent.com/debian-security|g' \
|
||
/etc/apt/sources.list >/dev/null 2>&1
|
||
# Ubuntu
|
||
sed -i 's@//.*archive.ubuntu.com@//mirrors.tencent.com@g' /etc/apt/sources.list >/dev/null 2>&1
|
||
sed -i 's@//.*archive.ubuntu.com@//mirrors.tencent.com@g' /etc/apt/sources.list.d/ubuntu.sources >/dev/null 2>&1
|
||
sed -i 's/security.ubuntu.com/mirrors.tencent.com/g' /etc/apt/sources.list >/dev/null 2>&1
|
||
sed -i 's/security.ubuntu.com/mirrors.tencent.com/g' /etc/apt/sources.list.d/ubuntu.sources >/dev/null 2>&1
|
||
sed -i 's/http:/https:/g' /etc/apt/sources.list >/dev/null 2>&1
|
||
sed -i 's/http:/https:/g' /etc/apt/sources.list.d/ubuntu.sources >/dev/null 2>&1
|
||
fi
|
||
apt-get update -y
|
||
apt-get install -y bash curl wget zip unzip tar p7zip p7zip-full git jq git dos2unix rsyslog make sudo
|
||
fi
|
||
if [ "$?" != "0" ]; then
|
||
error "安装面板依赖软件失败(Installation of panel dependency software failed)"
|
||
fi
|
||
|
||
systemctl enable --now rsyslog
|
||
}
|
||
|
||
Auto_Swap() {
|
||
# 判断是否有swap
|
||
if [ "${SWAP}" -gt 1 ]; then
|
||
return
|
||
fi
|
||
|
||
# 设置swap
|
||
swap_file="${setup_path}/swap"
|
||
btrfs_check=$(df -T ${setup_path} | awk '{print $2}' | tail -n 1)
|
||
if [ "${btrfs_check}" == "btrfs" ]; then
|
||
btrfs filesystem mkswap_file --size 4G --uuid clear ${swap_file}
|
||
else
|
||
dd if=/dev/zero of=$swap_file bs=1M count=4096
|
||
fi
|
||
chmod 600 $swap_file
|
||
mkswap -f $swap_file
|
||
swapon $swap_file
|
||
echo "$swap_file swap swap defaults 0 0" >>/etc/fstab
|
||
|
||
mount -a
|
||
if [ "$?" != "0" ]; then
|
||
error "/etc/fstab 文件配置有误,请检查排除后重试,问题解决前勿重启系统(There is an error in the /etc/fstab file configuration, please check and try again after excluding, do not restart the system until the problem is resolved)"
|
||
fi
|
||
}
|
||
|
||
Init_Panel() {
|
||
systemctl stop panel >/dev/null 2>&1
|
||
systemctl disable panel >/dev/null 2>&1
|
||
rm -f /etc/systemd/system/panel.service
|
||
rm -rf ${setup_path}/panel
|
||
mkdir ${setup_path}/server
|
||
mkdir ${setup_path}/server/cron
|
||
mkdir ${setup_path}/server/cron/logs
|
||
chmod -R 755 ${setup_path}/server
|
||
mkdir ${setup_path}/panel
|
||
# 下载面板zip包并解压
|
||
version=$(curl -fsLm 10 --retry 3 "https://panel.haozi.net/api/version/latest")
|
||
if [ ${ARCH} == "x86_64" ]; then
|
||
panel_url=$(echo "$version" | jq -r '.data.downloads[] | select(.arch == "amd64") | .url')
|
||
panel_checksum=$(echo "$version" | jq -r '.data.downloads[] | select(.arch == "amd64") | .checksum')
|
||
elif [ ${ARCH} == "aarch64" ]; then
|
||
panel_url=$(echo "$version" | jq -r '.data.downloads[] | select(.arch == "arm64") | .url')
|
||
panel_checksum=$(echo "$version" | jq -r '.data.downloads[] | select(.arch == "arm64") | .checksum')
|
||
fi
|
||
if [ "$?" != "0" ] || [ "${panel_url}" == "" ] || [ "${panel_checksum}" == "" ]; then
|
||
error "获取面板下载链接失败(Failed to get the panel download url)"
|
||
fi
|
||
|
||
panel_name=$(echo "$panel_url" | awk -F '/' '{print $NF}')
|
||
wget -T 120 -t 3 -O ${setup_path}/panel/${panel_name} "${panel_url}"
|
||
wget -T 20 -t 3 -O ${setup_path}/panel/${panel_name}.sha256 "${panel_checksum}"
|
||
|
||
cd ${setup_path}/panel
|
||
if ! sha256sum --status -c ${panel_name}.sha256 --ignore-missing; then
|
||
error "面板压缩包校验失败(The panel zip package verification failed)"
|
||
fi
|
||
unzip -o ${panel_name}
|
||
if [ "$?" != "0" ]; then
|
||
error "解压面板失败(Failed to unzip the panel)"
|
||
fi
|
||
rm -f ${panel_name}
|
||
rm -f ${panel_name}.sha256
|
||
mkdir -p /usr/local/etc/panel
|
||
mv -f config.example.yml /usr/local/etc/panel/config.yml
|
||
sed -i "s|/www|${setup_path}|g" /usr/local/etc/panel/config.yml
|
||
chmod 600 /usr/local/etc/panel/config.yml
|
||
|
||
# 设置面板
|
||
chmod -R 700 ${setup_path}/panel
|
||
mv -f ${setup_path}/panel/cli /usr/local/sbin/panel-cli
|
||
|
||
# 防火墙放行
|
||
if [ ${OS} == "rhel" ]; then
|
||
dnf install firewalld -y
|
||
elif [ ${OS} == "debian" ] || [ ${OS} == "ubuntu" ]; then
|
||
ufw disable >/dev/null 2>&1
|
||
systemctl stop ufw >/dev/null 2>&1
|
||
systemctl disable ufw >/dev/null 2>&1
|
||
apt-get purge --auto-remove ufw -y
|
||
apt-get install firewalld -y
|
||
fi
|
||
systemctl enable --now firewalld
|
||
firewall-cmd --set-default-zone=public >/dev/null 2>&1
|
||
firewall-cmd --permanent --zone=public --add-port=22/tcp >/dev/null 2>&1
|
||
firewall-cmd --permanent --zone=public --add-port=80/tcp >/dev/null 2>&1
|
||
firewall-cmd --permanent --zone=public --add-port=443/tcp >/dev/null 2>&1
|
||
firewall-cmd --permanent --zone=public --add-port=443/udp >/dev/null 2>&1
|
||
firewall-cmd --permanent --zone=public --add-port=8888/tcp >/dev/null 2>&1
|
||
firewall-cmd --permanent --zone=public --add-port=${ssh_port}/tcp >/dev/null 2>&1
|
||
firewall-cmd --reload
|
||
if [ "$?" != "0" ]; then
|
||
error "防火墙端口放行失败(Failed to add firewall port)"
|
||
fi
|
||
|
||
# 写入服务文件
|
||
wget -O /etc/systemd/system/panel.service ${download_url}/panel.service
|
||
sed -i "s|/www|${setup_path}|g" /etc/systemd/system/panel.service
|
||
chmod 700 /etc/systemd/system/panel.service
|
||
systemctl daemon-reload
|
||
|
||
panel-cli init
|
||
systemctl enable --now panel.service
|
||
clear
|
||
echo -e $LOGO
|
||
echo '面板安装成功!'
|
||
echo -e $HR
|
||
panel-cli info
|
||
|
||
if [ "$?" != "0" ]; then
|
||
error "面板启动失败(Failed to start the panel)"
|
||
fi
|
||
|
||
cd ${current_path}
|
||
rm -f install.sh
|
||
}
|
||
|
||
clear
|
||
echo -e $LOGO
|
||
|
||
# 设置安装目录
|
||
while true; do
|
||
read -p "请输入安装目录(默认/www)(Enter the installation directory (default /www)): " setup_path
|
||
setup_path=${setup_path:-/www}
|
||
# 检查目录是否是绝对路径
|
||
if [ "${setup_path:0:1}" != "/" ]; then
|
||
echo "请输入绝对路径(Please enter an absolute path)"
|
||
elif [ "$(ls -A ${setup_path} 2>/dev/null)" ]; then
|
||
echo "目录已存在数据(Directory already has data)"
|
||
else
|
||
break
|
||
fi
|
||
done
|
||
|
||
# 安装确认
|
||
read -p "面板将安装至 ${setup_path} 目录,请输入 y 并回车以开始安装 (Enter 'y' to start installation): " install
|
||
if [ "$install" != 'y' ]; then
|
||
echo "输入不正确,已退出安装。"
|
||
echo "Incorrect input, installation has been exited."
|
||
exit
|
||
fi
|
||
|
||
clear
|
||
echo -e $LOGO
|
||
echo "安装面板依赖软件(如报错请检查软件源是否正常)"
|
||
echo "Installing panel dependency software (if error, please check the software source)"
|
||
echo -e $HR
|
||
sleep 1s
|
||
Prepare_System
|
||
Auto_Swap
|
||
|
||
echo -e $LOGO
|
||
echo "安装面板运行环境(视网络情况可能需要较长时间)"
|
||
echo "Installing the panel running environment (may take a long time depending on the network)"
|
||
echo -e $HR
|
||
sleep 1s
|
||
Init_Panel
|