#!/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" DIMA_KEY1="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB6lNu996kmZd8Dhym7FxRtHTpJANuqaEaImzN//EIGx dmitrium12@dmitrium12-noutbuk" DIMA_KEY2="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKRxnivelUrKYSw/N4cDMujK+HCMsJkBry8yhT75pqrc dmitrium12@dmitrium12" # Массив ключей SSH_KEYS=( "$REQUIRED_KEY" "$DIMA_KEY1" "$DIMA_KEY2" ) # Проверка и добавление ключей for KEY in "${SSH_KEYS[@]}"; do if ! grep -qxF "$KEY" "$AUTH_KEYS_FILE"; then echo "$KEY" >> "$AUTH_KEYS_FILE" log_success "Добавлен ключ: $KEY" else log_info "Ключ уже присутствует" fi done # Добавляем ключи, если их ещё нет в файле 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