#!/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-ключи обработаны" # === Создание директорий под Docker === log_info "Создаю Docker директории и конфиги..." safe_mkdir "/opt/wordpress" safe_mkdir "/opt/npm" safe_mkdir "/opt/dockge" safe_mkdir "/opt/uptime-kuma" safe_mkdir "/opt/watchtower" # === WordPress конфиг === cat < /opt/wordpress/php.ini upload_max_filesize = 64M post_max_size = 64M max_execution_time = 300 max_input_time = 300 EOF # === Создание .env для WordPress === safe_mkdir "/opt/wordpress" cat < /opt/wordpress/.env # ========================= # Database Configuration # ========================= DB_NAME=wordpressdbname DB_USER=wordpressuser DB_PASSWORD=$(generate_password 16) # ========================= # WordPress Settings # ========================= WP_DEBUG=false WP_DEBUG_LOG=false TZ=Asia/Krasnoyarsk WP_DOMAIN= EOF chmod 600 /opt/wordpress/.env log_success "WordPress .env файл сгенерирован" # === Создание docker-compose.yml для WordPress === cat < /opt/wordpress/docker-compose.yml services: wordpress: container_name: wordpress image: wordpress:6.5-php8.2-apache restart: unless-stopped depends_on: db: condition: service_healthy env_file: - .env environment: WORDPRESS_CONFIG_EXTRA: | define('WP_DEBUG', \${WP_DEBUG}); define('WP_DEBUG_LOG', \${WP_DEBUG_LOG}); define('WP_HOME', 'https://\${WP_DOMAIN}'); define('WP_SITEURL', 'https://\${WP_DOMAIN}'); date_default_timezone_set('Asia/Krasnoyarsk'); volumes: # Контент WordPress с хоста - ./wp-content/uploads:/var/www/html/wp-content/uploads - ./wp-content/plugins:/var/www/html/wp-content/plugins - ./wp-content/themes:/var/www/html/wp-content/themes - ./wp-content/mytheme:/var/www/html/wp-content/themes/mytheme # Настройки PHP - ./config/uploads.ini:/usr/local/etc/php/conf.d/uploads.ini:ro - ./config/php.ini:/usr/local/etc/php/php.ini:ro # Логи Apache - ./logs/wordpress:/var/log/apache2 # Бэкапы и дополнительные данные - ./backups:/backups # Если wp-config.php существует как **файл**, можно раскомментировать строку ниже # - ./config/wp-config.php:/var/www/html/wp-config.php:ro #ports: #- "8080:80" networks: - wordpress_net - proxy healthcheck: test: ["CMD", "curl", "-f", "http://localhost/wp-admin/install.php"] interval: 30s timeout: 10s retries: 3 start_period: 30s db: container_name: wordpress-db image: mysql:8.0 restart: unless-stopped env_file: - .env environment: MYSQL_RANDOM_ROOT_PASSWORD: 'yes' TZ: \${TZ} volumes: - ./data/mysql:/var/lib/mysql - ./config/my.cnf:/etc/mysql/conf.d/custom.cnf:ro - ./logs/mysql:/var/log/mysql - ./backups/db:/docker-entrypoint-initdb.d command: - --default-time-zone=+07:00 - --character-set-server=utf8mb4 - --collation-server=utf8mb4_unicode_ci networks: - wordpress_net healthcheck: test: ["CMD-SHELL", "mysqladmin ping -h localhost -u\${DB_USER} -p\${DB_PASSWORD} || exit 1"] interval: 10s timeout: 5s retries: 5 start_period: 30s #phpmyadmin: #container_name: wordpress-phpmyadmin #image: phpmyadmin:latest #restart: unless-stopped #depends_on: #db: #condition: service_healthy #environment: #PMA_HOST: db #PMA_USER: \${DB_USER} #PMA_PASSWORD: \${DB_PASSWORD} #PMA_PORT: 3306 #TZ: \${TZ} #networks: #- wordpress_net #- proxy # Если нужно прямое подключение, можно открыть порт: # ports: # - "8080:80" networks: wordpress_net: driver: bridge proxy: external: true EOF # Генерация паролей и .env safe_mkdir "/opt/npm" cat < /opt/npm/.env # ========================= # Database Configuration # ========================= DB_ROOT_PASSWORD=$(generate_password 16) DB_NAME=npm_db_1 DB_USER=db_admin_user_npm_db DB_USER_PASSWORD=$(generate_password 16) EOF chmod 600 /opt/npm/.env log_success "NPM .env файл сгенерирован" # Генерация docker-compose.yml для NPM cat < /opt/npm/docker-compose.yml services: npm: image: jc21/nginx-proxy-manager:latest container_name: npm restart: unless-stopped ports: - "80:80" - "443:443" - "8181:81" env_file: - .env volumes: - "./data:/data" - "./letsencrypt:/etc/letsencrypt" networks: - "proxy" - "npm_net" extra_hosts: - "host.docker.internal:host-gateway" db: image: jc21/mariadb-aria:latest container_name: npm_db restart: unless-stopped env_file: - .env volumes: - "./mysql:/var/lib/mysql" networks: - "npm_net" networks: npm_net: internal: true proxy: external: true EOF # Сохраняем пароли в защищенный файл cat < /opt/npm/.env # ========================= # Database Configuration # ========================= DB_ROOT_PASSWORD=$(generate_password 16) DB_NAME=npm_db_1 DB_USER=db_admin_user_npm_db DB_USER_PASSWORD=$(generate_password 16) EOF chmod 600 /opt/npm/.env # Создаем директорию кастомного конфига safe_mkdir "/opt/npm/data/nginx/custom" # Создание конфигурации Nginx cat > /opt/npm/data/nginx/custom/server_proxy.conf <<'CONFIG' # ================================================ # Глобальные редиректы для всех доменов NPM # ================================================ # Перенаправление HTTP → HTTPS if ($scheme = http) { return 301 https://$host$request_uri; } # Перенаправление с www → non-www (кроме специальных случаев) if ($host ~* ^www\.(?.+)$) { # Исключение для доменов, где www должен вести на другое место # Если нужно исключить определенные домены, добавьте их здесь # if ($domain = "special-domain.com") { break; } return 301 https://$domain$request_uri; } CONFIG # Создание скрипта www.sh cat > /opt/npm/www.sh <<'SCRIPT' #!/bin/bash # Скрипт для применения конфигурации Nginx и перезагрузки сервиса mkdir -p /opt/npm/data/nginx/custom cat > /opt/npm/data/nginx/custom/server_proxy.conf <<'CONFIG' # ================================================ # Глобальные редиректы для всех доменов NPM # ================================================ # Перенаправление HTTP → HTTPS if ($scheme = http) { return 301 https://$host$request_uri; } # Перенаправление с www → non-www (кроме специальных случаев) if ($host ~* ^www\.(?.+)$) { # Исключение для доменов, где www должен вести на другое место # Если нужно исключить определенные домены, добавьте их здесь # if ($domain = "special-domain.com") { break; } return 301 https://$domain$request_uri; } CONFIG SCRIPT # Делаем скрипт исполняемым chmod +x /opt/npm/www.sh # === Dockge конфиг === cat < /opt/dockge/docker-compose.yml services: dockge: image: louislam/dockge:1 container_name: dockge restart: unless-stopped volumes: - /var/run/docker.sock:/var/run/docker.sock - ./data:/app/data - /opt:/opt/stacks environment: - DOCKGE_STACKS_DIR=/opt/stacks #- DOCKGE_ENABLE_CONSOLE=true #ports: #- "5001:5001" networks: - proxy networks: proxy: external: true EOF # === Uptime Kuma конфиг === cat < /opt/uptime-kuma/docker-compose.yml services: uptime-kuma: image: louislam/uptime-kuma:1 container_name: uptime-kuma restart: unless-stopped volumes: - ./data:/app/data - /var/run/docker.sock:/var/run/docker.sock #ports: #- "3001:3001" networks: - uptime-net - proxy networks: uptime-net: driver: bridge proxy: external: true EOF # === Watchtower конфиг === cat < /opt/watchtower/docker-compose.yml services: watchtower: image: containrrr/watchtower:latest container_name: watchtower restart: unless-stopped volumes: - /var/run/docker.sock:/var/run/docker.sock command: --interval 3600 --cleanup EOF # Оповещение о успешном создании базовых контейнеров log_success "Docker конфиги созданы" # === Обновление системы и установка пакетов === run_cmd "sudo apt update && sudo apt upgrade -y" "Обновление системы" run_cmd "sudo apt install -y \ mc \ gcc \ btop \ hollywood \ curl \ htop \ git \ ufw \ ndisc6 \ fail2ban \ socat \ python3-pip \ micro \ 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 службы" # === Создание Docker сети === log_info "Создание Docker сети proxy..." if ! docker network inspect proxy >/dev/null 2>&1; then if docker network create --driver bridge proxy; then log_success "Docker сеть proxy создана" else log_error "Не удалось создать Docker сеть proxy" fi else log_success "Docker сеть proxy уже существует" fi # === Улучшение nano === log_info "Настройка nano..." HOME_DIR="$HOME" if [[ -f "$HOME_DIR/.nanorc" ]]; then mv "$HOME_DIR/.nanorc" "$HOME_DIR/.nanorc.bak" log_info "Создан backup .nanorc" fi cat > "$HOME_DIR/.nanorc" <<'EOF' set linenumbers set softwrap set tabsize 4 set tabstospaces set autoindent set smarthome set indicator set positionlog #set mouse set fill 80 EOF safe_mkdir "$HOME_DIR/.nano" if [[ ! -d "$HOME_DIR/.nano/syntax" ]]; then if git clone https://github.com/scopatz/nanorc.git "$HOME_DIR/.nano/syntax" 2>/dev/null; then log_success "Синтаксис для nano установлен" else log_warning "Не удалось установить синтаксис для nano" fi fi # === Установка 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}}"' 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 # === Финал === echo log_success "🎉 Установка завершена!" echo log_info "📝 Важная информация:" echo " - Пароли для NPM сохранены в: /opt/npm/.env" 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