From c6b66322df8c84cab05310baf4e9752258526e82 Mon Sep 17 00:00:00 2001 From: Verum Date: Fri, 21 Nov 2025 18:16:38 +0000 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D1=82?= =?UTF-8?q?=D1=8C=20setup.sh?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- setup.sh | 1137 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1137 insertions(+) create mode 100644 setup.sh diff --git a/setup.sh b/setup.sh new file mode 100644 index 0000000..32d6507 --- /dev/null +++ b/setup.sh @@ -0,0 +1,1137 @@ +#!/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 + +# Создание паролей для WordPress +cat < /opt/wordpress/.env +# Database +DB_NAME=wordpressdbname +DB_USER=wordpressuser +DB_PASSWORD=$(generate_password 16) + +# WordPress +WP_DEBUG=false +WP_DEBUG_LOG=false +WP_DOMAIN= +EOF + +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 + environment: + WORDPRESS_DB_HOST: db + WORDPRESS_DB_USER: ${DB_USER} + WORDPRESS_DB_PASSWORD: ${DB_PASSWORD} + WORDPRESS_DB_NAME: ${DB_NAME} + TZ: ${TZ} + WP_DOMAIN: ${WP_DOMAIN} + 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 + environment: + MYSQL_DATABASE: ${DB_NAME} + MYSQL_USER: ${DB_USER} + MYSQL_PASSWORD: ${DB_PASSWORD} + 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 + + + +# === NPM конфиг с безопасными паролями === +cat < /opt/npm/docker-compose.yml +services: + app: + image: jc21/nginx-proxy-manager:latest + container_name: npm + restart: unless-stopped + ports: + - "80:80" + - "443:443" + - "8181:81" + environment: + DB_MYSQL_HOST: "db" + DB_MYSQL_PORT: "3306" + DB_MYSQL_USER: "${DB_USER}" + DB_MYSQL_PASSWORD: "${DB_USER_PASSWORD}" + DB_MYSQL_NAME: "${DB_NAME}" + 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 + environment: + MYSQL_ROOT_PASSWORD: "${DB_ROOT_PASSWORD}" + MYSQL_DATABASE: "${DB_NAME}" + MYSQL_USER: "${DB_USER}" + MYSQL_PASSWORD: "${DB_USER_PASSWORD}" + 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 \ + 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