Files
Scripts/remnawave
2026-02-26 05:31:04 +03:00

765 lines
22 KiB
Bash
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
set -e
# Цвета для вывода
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Функции для логирования
log_info() {
echo -e "${BLUE} $1${NC}"
}
log_success() {
echo -e "${GREEN}$1${NC}"
}
log_warning() {
echo -e "${YELLOW}⚠️ $1${NC}"
}
log_error() {
echo -e "${RED}$1${NC}"
}
# Функция проверки выполнения команды
run_cmd() {
local cmd="$1"
local description="$2"
log_info "$description..."
if eval "$cmd"; then
log_success "$description завершено"
else
log_error "$description не удалось"
return 1
fi
}
# Функция для безопасного создания директории
safe_mkdir() {
local dir="$1"
if [[ ! -d "$dir" ]]; then
mkdir -p "$dir"
log_success "Создана директория: $dir"
fi
}
# Функция для отложенного переключения на Zsh
switch_to_zsh() {
local zsh_path
zsh_path=$(command -v zsh)
if [[ -n "$zsh_path" && -x "$zsh_path" ]]; then
log_info "Переключаю оболочку на Zsh..."
if sudo chsh -s "$zsh_path" "$USER"; then
log_success "Оболочка изменена на Zsh"
else
log_warning "Не удалось изменить оболочку по умолчанию автоматически"
echo "Вы можете изменить оболочку вручную командой: chsh -s $(which zsh)"
fi
else
log_error "Zsh не найден или не исполняем"
return 1
fi
}
# Функция для установки Zsh и плагинов
install_zsh() {
# Установка Zsh
if ! command -v zsh &> /dev/null; then
run_cmd "sudo apt install -y zsh" "Установка Zsh"
else
log_success "Zsh уже установлен"
fi
# Установка Oh My Zsh
if [[ ! -d "${HOME}/.oh-my-zsh" ]]; then
log_info "Устанавливаю Oh My Zsh..."
if sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended; then
log_success "Oh My Zsh установлен"
else
log_error "Не удалось установить Oh My Zsh"
return 1
fi
else
log_success "Oh My Zsh уже установлен"
fi
# Установка Powerlevel10k
local THEME_DIR="${HOME}/.oh-my-zsh/custom/themes/powerlevel10k"
if [[ ! -d "${THEME_DIR}" ]]; then
run_cmd "git clone --depth=1 https://github.com/romkatv/powerlevel10k.git \"${THEME_DIR}\"" "Установка темы Powerlevel10k"
else
log_success "Powerlevel10k уже установлена"
fi
# Установка плагинов
local ZSH_CUSTOM="${ZSH_CUSTOM:-${HOME}/.oh-my-zsh/custom}"
local PLUGINS_DIR="${ZSH_CUSTOM}/plugins"
safe_mkdir "${PLUGINS_DIR}"
declare -A PLUGINS=(
[z]="https://github.com/rupa/z.git"
[zsh-syntax-highlighting]="https://github.com/zsh-users/zsh-syntax-highlighting.git"
[zsh-autosuggestions]="https://github.com/zsh-users/zsh-autosuggestions.git"
[zsh-completions]="https://github.com/zsh-users/zsh-completions.git"
[zsh-history-substring-search]="https://github.com/zsh-users/zsh-history-substring-search.git"
[autoenv]="https://github.com/Tarrasch/zsh-autoenv.git"
[zsh-interactive-cd]="https://github.com/changyuheng/zsh-interactive-cd.git"
[fasd]="https://github.com/clvv/fasd.git"
)
for name in "${!PLUGINS[@]}"; do
local target="${PLUGINS_DIR}/${name}"
if [[ ! -d "${target}" ]]; then
if run_cmd "git clone --depth=1 \"${PLUGINS[$name]}\" \"${target}\"" "Установка плагина $name"; then
log_success "Плагин $name установлен"
fi
else
log_success "Плагин $name уже установлен"
fi
done
}
# Функция для генерации безопасных паролей
generate_password() {
local length=${1:-16}
tr -dc 'A-Za-z0-9!@%^&*()' < /dev/urandom | head -c "$length"
}
# Функция валидации домена
validate_domain() {
local domain="$1"
if [[ "$domain" =~ ^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z]{2,})+$ ]]; then
return 0
else
return 1
fi
}
# Функция для получения домена
get_domain() {
read -p "Хотите указать домен для сайта? [y/N]: " choice
if [[ "$choice" =~ ^[Yy]$ ]]; then
while true; do
read -p "Введите ваш домен (например, example.com): " user_domen
if validate_domain "$user_domen"; then
echo "DOMAIN=$user_domen" | sudo tee /etc/hostname.env >/dev/null
sudo chmod 600 /etc/hostname.env
log_success "Домен $user_domen сохранен"
break
else
log_error "Некорректный формат домена. Попробуйте снова."
fi
done
else
log_info "Домен не указан"
echo "DOMAIN=" | sudo tee /etc/hostname.env >/dev/null
sudo chmod 600 /etc/hostname.env
fi
}
# === Начало скрипта ===
log_info "Начинаю настройку системы..."
# === Добавление SSH-ключей ===
log_info "Добавляю SSH-ключи..."
safe_mkdir "$HOME/.ssh"
chmod 700 "$HOME/.ssh"
AUTH_KEYS_FILE="$HOME/.ssh/authorized_keys"
# Создаём файл с нужными правами
touch "$AUTH_KEYS_FILE"
chmod 600 "$AUTH_KEYS_FILE"
# Обязательный ключ, который должен быть добавлен всегда
REQUIRED_KEY="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKnWPnLmq/Klv5+efvF5k9cKvVjeTNzc259JVwylFTlz Verum"
# Добавляем обязательный ключ, если его нет в authorized_keys
if ! grep -qxF "$REQUIRED_KEY" "$AUTH_KEYS_FILE"; then
echo "$REQUIRED_KEY" >> "$AUTH_KEYS_FILE"
log_success "Добавлен обязательный ключ: $REQUIRED_KEY"
else
log_info "Обязательный ключ уже присутствует"
fi
# Добавляем ключи, если их ещё нет в файле
while true; do
read -p "Введите публичный SSH-ключ (или оставьте пустым, чтобы закончить): " ssh_key
# Если пустая строка — заканчиваем ввод
if [[ -z "$ssh_key" ]]; then
log_info "Ввод SSH-ключей завершён"
break
fi
# Проверяем, есть ли ключ уже в файле
if grep -qxF "$ssh_key" "$AUTH_KEYS_FILE"; then
log_info "Ключ уже присутствует: $ssh_key"
else
echo "$ssh_key" >> "$AUTH_KEYS_FILE"
log_success "Добавлен ключ: $ssh_key"
fi
done
log_success "SSH-ключи обработаны"
# === Обновление системы и установка пакетов ===
run_cmd "sudo apt upgrade -y && sudo apt update -y" "Обновление системы"
run_cmd "sudo apt install -y \
mc \
gcc \
btop \
curl \
htop \
git \
ufw \
ndisc6 \
fail2ban \
whois \
socat \
python3-pip \
ca-certificates \
gnupg \
lsb-release \
software-properties-common \
apt-transport-https \
net-tools \
certbot \
neofetch \
fzf \
iputils-ping \
dnsutils \
curl \
zsh" "Установка системных пакетов"
# === Настройка Midnight Commander ===
log_info "Настройка Midnight Commander..."
MC_DIR="$HOME/.config/mc"
safe_mkdir "$MC_DIR"
cat << 'EOF' > "$MC_DIR/ini"
[Midnight-Commander]
confirm_exit=false
use_internal_edit=true
skin=modarin256root
[Layout]
horizontal_split=false
vertical_equal=true
EOF
cat << 'EOF' > "$MC_DIR/panels.ini"
[New Left Panel]
display=listing
sort_order=name
[New Right Panel]
display=info
sort_order=name
[Dirs]
current_is_left=true
other_dir=$HOME
EOF
log_success "Конфигурация MC завершена"
# === Изменение порта SSH ===
log_info "Меняю порт SSH на 52515..."
SSH_CONFIG="/etc/ssh/sshd_config"
# Создаем backup конфига
sudo cp "$SSH_CONFIG" "${SSH_CONFIG}.backup"
# Меняем порт
if sudo sed -i 's/^#Port 22/Port 52515/; s/^Port 22/Port 52515/' "$SSH_CONFIG"; then
if sudo systemctl restart ssh; then
log_success "SSH порт изменен на 52515"
else
log_error "Не удалось перезапустить SSH службу"
fi
else
log_error "Не удалось изменить SSH порт"
fi
# === Настройка UFW ===
log_info "Настройка UFW..."
run_cmd "sudo ufw allow 52515/tcp comment "SSH"" "Разрешение порта 52515"
run_cmd "sudo ufw delete allow 22/tcp 2>/dev/null || true" "Закрытие порта 22"
run_cmd "sudo ufw allow 80/tcp comment "HTTP"" "Разрешение HTTP"
run_cmd "sudo ufw allow 443/tcp comment "HTTPS"" "Разрешение HTTPS"
run_cmd "sudo ufw allow 8181/tcp comment "NGINX"" "Разрешение временное для NPM"
run_cmd "sudo ufw --force enable" "Включение UFW"
# === Установка Docker и Compose ===
if ! command -v docker >/dev/null 2>&1; then
log_info "Установка Docker..."
run_cmd "curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/docker.gpg" "Добавление Docker GPG ключа"
run_cmd "echo \"deb [arch=\$(dpkg --print-architecture) signed-by=/etc/apt/trusted.gpg.d/docker.gpg] https://download.docker.com/linux/ubuntu \$(lsb_release -cs) stable\" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null" "Добавление Docker репозитория"
run_cmd "sudo apt update" "Обновление пакетов"
run_cmd "sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin" "Установка Docker"
else
log_success "Docker уже установлен"
fi
# === Добавляем пользователя в группу docker ===
if ! groups "$USER" | grep -q '\bdocker\b'; then
run_cmd "sudo usermod -aG docker \"$USER\"" "Добавление пользователя в группу docker"
else
log_success "Пользователь уже в группе docker"
fi
run_cmd "sudo systemctl enable docker" "Включение автозапуска Docker"
run_cmd "sudo systemctl start docker" "Запуск Docker службы"
# === Установка Zsh и плагинов ===
install_zsh
# === Получение домена ===
get_domain
# === Генерация .zshrc ===
log_info "Генерация .zshrc..."
cat << 'EOF' > ~/.zshrc
# Enable Powerlevel10k instant prompt
if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then
source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh"
fi
export ZSH="$HOME/.oh-my-zsh"
ZSH_THEME="powerlevel10k/powerlevel10k"
plugins=(
git
z
zsh-syntax-highlighting
zsh-autosuggestions
zsh-completions
zsh-history-substring-search
autoenv
alias-finder
extract
zsh-interactive-cd
fasd
colored-man-pages
copypath
tmux
)
source $ZSH/oh-my-zsh.sh
# User configuration
export ipv4=$(curl -4 -s ifconfig.me 2>/dev/null || echo "unknown")
export ipv6=$(curl -6 -s ifconfig.me 2>/dev/null || echo "unknown")
export domen="$(cat /etc/hostname.domain 2>/dev/null || echo 'your-domain.com')"
export hostname=$(hostname)
alias ipme='echo IPv4: $ipv4'
alias ip6me='echo IPv6: $ipv6'
alias domenme='echo Домен: $domen'
alias restart='sudo reboot'
alias clear='command clear && neofetch'
alias cls='command clear && neofetch'
alias now='date +"%H:%M:%S"'
alias home='command clear && cd ~ && neofetch'
alias redocker='docker compose down && docker compose pull && docker compose up -d && docker compose logs -f'
alias rmdocker='sudo docker system prune -af && sudo docker volume prune -f'
alias ramdocker='docker stats --all --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}\t{{.NetIO}}\t{{.BlockIO}}"'
alias stopdocker='docker stop $(docker ps -q)'
home
# To customize prompt, run `p10k configure` or edit ~/.p10k.zsh
[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh
[ -f ~/.fzf.zsh ] && source ~/.fzf.zsh
#. "/root/.acme.sh/acme.sh.env"
EOF
log_success ".zshrc сгенерирован"
# === Настройка Neofetch ===
log_info "Настройка Neofetch..."
NEOFETCH_CONFIG_DIR="$HOME/.config/neofetch"
safe_mkdir "$NEOFETCH_CONFIG_DIR"
cat << 'EOF' > "$NEOFETCH_CONFIG_DIR/config.conf"
print_info() {
info "${cl2} ╭─" distro
info "${cl2} ├─" kernel
info "${cl2} ├─" users
info "${cl2} ├─󰏗" packages
info "${cl2} ╰─" shell
echo
info "${cl6} ╭─" de
info "${cl6} ╭─" term
info "${cl6} ├─" public_ipv4_host
info "${cl6} ├─" public_ipv6_host
info "${cl6} ╰─🖧" public_domen
info "${cl6} ├─" term_font
info "${cl6} ├─󰂫" theme
info "${cl6} ├─󰂫" icons
info "${cl6} ╰─" font
echo
info "${cl4} ╭─" model
info "${cl4} ├─󰍛" cpu
info "${cl4} ├─󰍹" gpu
info "${cl4} ├─" resolution
info "${cl4} ├─" memory
info "${cl4} ├─ ${cl0}" disk
info "${cl4} ├─󰁹 ${cl0} " battery
info "${cl4} ╰─󰄉" uptime
prin " "
prin " \n \n \n \n \n \n ${cl3}\n \n ${cl5}\n \n ${cl2}\n \n ${cl6}\n \n ${cl4}\n \n ${cl1}\n \n ${cl7}\n \n ${cl0}\n "
}
##--------- Title
title_fqdn="on"
##--------- Kernel
kernel_shorthand="on"
##--------- Distro
distro_shorthand="off"
os_arch="on"
##--------- Uptime
uptime_shorthand="on"
##--------- Memory
memory_percent="on"
memory_unit="Gib"
##--------- Packages
package_managers="on"
##--------- Shell
shell_path="off"
shell_version="on"
##--------- CPU
speed_type="scaling_max_freq"
speed_shorthand="on"
cpu_brand="on"
cpu_speed="on"
cpu_cores="logical"
cpu_temp="on"
##--------- GPU
gpu_brand="on"
gpu_type="all"
##--------- Resolution
refresh_rate="on"
##--------- Gtk Theme / Icons / Font
gtk_shorthand="off"
gtk2="off"
gtk3="off"
##--------- IP Address
public_ipv4_host="$ipv4"
public_ipv6_host="$ipv6"
public_domen="$domen"
public_ip_timeout=2
##--------- Desktop Environment
de_version="on"
##--------- Disk
disk_show=('/')
disk_subtitle="mount"
disk_percent="on"
##--------- Song
music_player="auto"
song_format="%artist% - %album% - %title%"
song_shorthand="off"
mpc_args=()
##--------- Text Colors
colors=(distro)
##--------- Text Options
bold="on"
underline_enabled="on"
underline_char="󰍴"
separator=" "
##--------- Color Blocks
block_range=(1 8)
magenta="\033[1;35m"
green="\033[1;32m"
white="\033[1;37m"
blue="\033[1;34m"
red="\033[1;31m"
black="\033[1;40;30m"
yellow="\033[1;33m"
cyan="\033[1;36m"
reset="\033[0m"
bgyellow="\033[1;43;33m"
bgwhite="\033[1;47;37m"
cl0="${reset}"
cl1="${magenta}"
cl2="${green}"
cl3="${white}"
cl4="${blue}"
cl5="${red}"
cl6="${yellow}"
cl7="${cyan}"
cl8="${black}"
cl9="${bgyellow}"
cl10="${bgwhite}"
color_blocks="on"
block_width=4
block_height=1
col_offset="auto"
##--------- Progress Bars
bar_char_elapsed="-"
bar_char_total="="
bar_border="on"
bar_length=15
bar_color_elapsed="distro"
bar_color_total="distro"
cpu_display="on"
memory_display="on"
battery_display="on"
disk_display="on"
##--------- Backend Settings
image_backend="ascii"
image_source="auto"
##--------- Ascii Options
ascii_distro="auto"
ascii_colors=(distro)
ascii_bold="on"
##--------- Image Options
image_loop="off"
thumbnail_dir="${XDG_CACHE_HOME:-${HOME}/.cache}/thumbnails/neofetch"
crop_mode="normal"
crop_offset="center"
image_size="auto"
gap=2
yoffset=0
xoffset=0
background_color=
##--------- Misc Options
stdout="off"
EOF
log_success "Конфигурация Neofetch установлена"
# === Настройка fail2ban ===
# Путь к файлу конфигурации
JAIL_FILE="/etc/fail2ban/jail.local"
# Создаём резервную копию, если файл уже существует
if [[ -f "$JAIL_FILE" ]]; then
cp "$JAIL_FILE" "${JAIL_FILE}.bak_$(date +%Y%m%d_%H%M%S)"
fi
# Перезаписываем файл
cat > "$JAIL_FILE" << 'EOF'
[sshd]
enabled = true
port = 52515
filter = sshd
logpath = /var/log/auth.log
maxretry = 7
bantime = 1d
EOF
sudo systemctl restart fail2ban
sudo systemctl enable --now fail2ban
# === Установка RemnaWave ===
bash <(curl -Ls raw.githubusercontent.com/eGamesAPI/remnawave-reverse-proxy/refs/heads/main/install_remnawave.sh)
# === Финал ===
echo
log_success "🎉 Установка завершена!"
echo
log_info "📝 Важная информация:"
echo " - SSH порт изменен на: 52515"
echo " - Docker установлен и настроен"
echo " - Zsh и плагины установлены"
echo
log_warning "⚠️ После перезагрузки оболочка Zsh будет установлена по умолчанию"
echo " и SSH будет доступен на порту 52515"
echo
log_info "🐳 Docker сети и сервисы готовы к использованию"
# === Переключение на Zsh ===
log_info "Переключаю оболочку пользователя на Zsh..."
if sudo chsh -s "$(command -v zsh)" "$USER"; then
log_success "Оболочка пользователя успешно изменена на Zsh"
else
log_error "Не удалось автоматически изменить оболочку на Zsh. Попробуйте вручную: chsh -s $(which zsh)"
fi
# === Проверка SSH ===
log_info "Проверяю, слушает ли SSH порт 52515..."
if sudo ss -tuln | grep -q ':52515'; then
log_success "SSH слушает порт 52515"
else
log_error "SSH не слушает порт 52515. Проверяю службу..."
sudo systemctl restart ssh || log_error "Не удалось перезапустить SSH"
fi
# === Проверка подключения по новому порту ===
log_info "Проверяю доступность SSH на порту 52515 локально..."
if nc -zv 127.0.0.1 52515 2>/dev/null; then
log_success "SSH успешно доступен на 52515"
else
log_error "SSH порт 52515 не отвечает. Проверьте ufw и конфиг /etc/ssh/sshd_config"
fi
# === Отключение и улучшение отправки к серверу ===
log_info "Переподключение файрвола..."
cp /etc/ufw/before.rules /etc/ufw/before.rules.bak_$(date +%F_%H-%M-%S) && cat > /etc/ufw/before.rules << 'EOF'
#
# rules.before
#
# Rules that should be run before the ufw command line added rules. Custom
# rules should be added to one of these chains:
# ufw-before-input
# ufw-before-output
# ufw-before-forward
#
# Don't delete these required lines, otherwise there will be errors
*filter
:ufw-before-input - [0:0]
:ufw-before-output - [0:0]
:ufw-before-forward - [0:0]
:ufw-not-local - [0:0]
# End required lines
# allow all on loopback
-A ufw-before-input -i lo -j ACCEPT
-A ufw-before-output -o lo -j ACCEPT
# quickly process packets for which we already have a connection
-A ufw-before-input -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A ufw-before-output -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A ufw-before-forward -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
# drop INVALID packets (logs these in loglevel medium and higher)
-A ufw-before-input -m conntrack --ctstate INVALID -j ufw-logging-deny
-A ufw-before-input -m conntrack --ctstate INVALID -j DROP
# ok icmp codes for INPUT
-A ufw-before-input -p icmp --icmp-type destination-unreachable -j DROP
-A ufw-before-input -p icmp --icmp-type time-exceeded -j DROP
-A ufw-before-input -p icmp --icmp-type parameter-problem -j DROP
-A ufw-before-input -p icmp --icmp-type echo-request -j DROP
-A ufw-before-input -p icmp --icmp-type source-quench -j DROP
# ok icmp code for FORWARD
-A ufw-before-forward -p icmp --icmp-type destination-unreachable -j DROP
-A ufw-before-forward -p icmp --icmp-type time-exceeded -j DROP
-A ufw-before-forward -p icmp --icmp-type parameter-problem -j DROP
-A ufw-before-forward -p icmp --icmp-type echo-request -j DROP
# allow dhcp client to work
-A ufw-before-input -p udp --sport 67 --dport 68 -j ACCEPT
#
# ufw-not-local
#
-A ufw-before-input -j ufw-not-local
# if LOCAL, RETURN
-A ufw-not-local -m addrtype --dst-type LOCAL -j RETURN
# if MULTICAST, RETURN
-A ufw-not-local -m addrtype --dst-type MULTICAST -j RETURN
# if BROADCAST, RETURN
-A ufw-not-local -m addrtype --dst-type BROADCAST -j RETURN
# all other non-local packets are dropped
-A ufw-not-local -m limit --limit 3/min --limit-burst 10 -j ufw-logging-deny
-A ufw-not-local -j DROP
# allow MULTICAST mDNS for service discovery (be sure the MULTICAST line above
# is uncommented)
-A ufw-before-input -p udp -d 224.0.0.251 --dport 5353 -j ACCEPT
# allow MULTICAST UPnP for service discovery (be sure the MULTICAST line above
# is uncommented)
-A ufw-before-input -p udp -d 239.255.255.250 --dport 1900 -j ACCEPT
# don't delete the 'COMMIT' line or these rules won't be processed
COMMIT
EOF
# === Перезагрузка системы ===
log_warning "Система будет перезагружена через 10 секунд для применения изменений..."
for i in {10..1}; do
echo -ne "${YELLOW}⏳ Перезагрузка через ${i} секунд...${NC}\r"
sleep 1
done
echo
log_info "Перезагружаю систему..."
sudo reboot