# Документация: Система бэкапов и мониторинга VPS # Оглавление [Общая архитектура](#общая-архитектура) 1. [Настройка SSH](#1-настройка-ssh) - 1.1 [Изменение порта SSH](#изменение-порта-ssh) - 1.2 [Отключение парольной аутентификации](#отключение-парольной-аутентификации) - 1.3 [Генерация SSH-ключа](#генерация-ssh-ключа) 2. [CrowdSec](#2-crowdsec) - 2.1 [Установка и настройка](#установка-и-настройка) - 2.2 [Проверка работы](#проверка-работы) 3. [Настройка Nextcloud](#3-настройка-nextcloud) - 3.1 [Создание пользователя hermes](#создание-пользователя-hermes) - 3.2 [Создание App Password](#создание-app-password) - 3.3 [Создание структуры папок](#создание-структуры-папок) 4. [Настройка Яндекс Диска](#4-настройка-яндекс-диска) - 4.1 [Регистрация приложения](#регистрация-приложения) - 4.2 [Авторизация rclone](#авторизация-rclone) - 4.3 [Создание remote в rclone](#создание-remote-в-rclone) 5. [Systemd Credentials](#5-systemd-credentials) 6. [Скрипты бэкапов](#6-скрипты-бэкапов) - 6.1 [logs-backup.sh (инкрементные бэкапы)](#logs-backupsh-инкрементные-бэкапы) - 6.2 [logs-full-backup.sh (полный бэкап)](#logs-full-backupsh-полный-бэкап) - 6.3 [backup.sh (бэкап 3x-ui)](#backupsh-бэкап-3x-ui) 7. [Systemd Units и Timers](#7-systemd-units-и-timers) - 7.1 [logs-backup.service и timer](#logs-backupservice-и-timer) - 7.2 [logs-full-backup.service и timer](#logs-full-backupservice-и-timer) - 7.3 [xui-backup.service и timer](#xui-backupservice-и-timer) - 7.4 [Активация timers](#активация-timers) 8. [Автоматизация на Nextcloud](#8-автоматизация-на-nextcloud) - 8.1 [nextcloud-transit-processor.sh](#nextcloud-transit-processorsh) - 8.2 [Добавление в cron](#добавление-в-cron) 9. [Расписание и ротация](#9-расписание-и-ротация) 10. [Безопасность](#10-безопасность) - 10.1 [Защита от компрометации VPS](#защита-от-компрометации-vps) - 10.2 [Изоляция через transit](#изоляция-через-transit) - 10.3 [Шифрование credentials](#шифрование-credentials) 11. [Мониторинг и проверка](#11-мониторинг-и-проверка) - 11.1 [Проверка работы timers](#проверка-работы-timers) - 11.2 [Проверка логов](#проверка-логов) - 11.3 [Проверка файлов на Яндекс Диске](#проверка-файлов-на-яндекс-диске) - 11.4 [Проверка transit на Nextcloud](#проверка-transit-на-nextcloud) - 11.5 [Проверка финальных папок](#проверка-финальных-папок) 12. [Добавление нового VPS](#12-добавление-нового-vps) 13. [Очистка истории и запуск мониторинга](#13-очистка-истории-и-запуск-мониторинга) - 13.1 [Сброс offset](#сброс-offset) - 13.2 [Очистка bash history](#очистка-bash-history) - 13.3 [Ротация auth.log](#ротация-authlog) - 13.4 [Очистка старых бэкапов](#очистка-старых-бэкапов) - 13.5 [Тестовый запуск](#тестовый-запуск) 14. [Итоговый статус системы](#14-итоговый-статус-системы) 15. [Дальнейшее развитие](#15-дальнейшее-развитие) - 15.1 [Алерты об успешных входах](#алерты-об-успешных-входах) - 15.2 [Google Drive как третье хранилище](#google-drive-как-третье-хранилище) - 15.3 [Шифрование бэкапов через rclone crypt](#шифрование-бэкапов-через-rclone-crypt) ## Общая архитектура Система автоматического бэкапирования состоит из трёх компонентов: 1. **VPS (Charon-vpn)** — сервер, с которого собираются бэкапы 2. **Nextcloud (nc.zailon.ru)** — основное хранилище с автоматической обработкой через transit-папку 3. **Яндекс Диск** — резервное хранилище Поток данных: ```mermaid graph TD A[VPS Charon-vpn] -->|logs-backup.sh| B[Nextcloud: transit/Charon-vpn/Logs] A -->|xui-backup.sh| C[Nextcloud: transit/Charon-vpn/OlimpVPN] A -->|rclone| D[Яндекс Диск: Olimp/Logs/Charon-vpn] A -->|rclone| E[Яндекс Диск: Olimp/VPN/Charon-vpn] B -->|cron: nextcloud-transit-processor.sh| F[Nextcloud: Admin/Olimp/OlimpBackup/Charon-vpn/Logs] C -->|cron: nextcloud-transit-processor.sh| G[Nextcloud: Admin/Olimp/OlimpBackup/Charon-vpn/OlimpVPN] ``` ## 1. Настройка SSH ### Изменение порта SSH Создаём override для ssh.service: ```bash mkdir -p /etc/systemd/system/ssh.service.d cat > /etc/systemd/system/ssh.service.d/override.conf <<'EOF' [Service] ExecStart= ExecStart=/usr/sbin/sshd -D -p 45132 EOF systemctl daemon-reload systemctl restart ssh ``` **Теория:** Override-файл позволяет изменить параметры запуска systemd-сервиса без редактирования основного unit-файла. Первая строка `ExecStart=` очищает оригинальную команду, вторая задаёт новую с портом 45132. ### Отключение парольной аутентификации ```bash # В файле /etc/ssh/sshd_config установить: PasswordAuthentication no PubkeyAuthentication yes ChallengeResponseAuthentication no systemctl restart ssh ``` **Теория:** После отключения `PasswordAuthentication` вход по паролю невозможен — только SSH-ключи. Это защищает от брутфорса. ### Генерация SSH-ключа на клиенте ```bash ssh-keygen -t ed25519 -C "charon-vpn" ssh-copy-id -p 45132 root@server-ip ``` **Теория:** Ed25519 — современный алгоритм, быстрее и безопаснее RSA. Ключ копируется на сервер через `ssh-copy-id`. ## 2. CrowdSec ### Установка и настройка ```bash curl -s https://packagecloud.io/install/script/gpg/script.deb.sh | sudo bash apt-get install crowdsec ``` **Теория:** CrowdSec анализирует логи в реальном времени. При обнаружении атаки (брутфорс SSH) автоматически добавляет IP в бан через iptables/nftables. ### Проверка работы ```bash cscli bouncers list cscli decisions list ``` ## 3. Настройка Nextcloud ### Создание пользователя hermes 1. Зайти в Nextcloud как администратор 2. Настройки → Пользователи → Создать пользователя 3. Имя: `hermes`, пароль: любой (запомнить) 4. Не давать никаких прав, только базовый доступ ### Создание App Password 1. Зайти в Nextcloud как `hermes` 2. Настройки → Безопасность → Пароли приложений 3. Создать пароль с именем "Charon-vpn-backup" 4. Скопировать сгенерированный пароль **Теория:** App Password — токен для доступа к Nextcloud без использования основного пароля. Можно отозвать в любой момент без изменения основного пароля. ### Создание структуры папок на сервере Nextcloud ```bash mkdir -p /mnt/cloud/data/hermes/files/transit/Charon-vpn/Logs mkdir -p /mnt/cloud/data/hermes/files/transit/Charon-vpn/OlimpVPN chown -R www-data:www-data /mnt/cloud/data/hermes/files/transit/ sudo -u www-data php /var/www/nextcloud/occ files:scan hermes ``` **Теория:** Папка `transit` — временная зона, куда VPS загружает файлы. Скрипт на Nextcloud автоматически перемещает их в финальные папки. Это защищает от удаления файлов, если VPS скомпрометирован (hermes не имеет прав на удаление в финальных папках). ## 4. Настройка Яндекс Диска ### Регистрация приложения 1. Зайти на https://oauth.yandex.ru/client/new 2. Название: "Charon-vpn backup" 3. Платформы: Веб-сервисы 4. Callback URL: `https://localhost` 5. Права: `disk:write` (только запись) ### Авторизация rclone ```bash rclone authorize "yandex" "CLIENT_ID" "CLIENT_SECRET" ``` Скопировать токен из вывода. ### Создание remote в rclone ```bash rclone config ``` Выбрать: - n) New remote - name> yandex - Storage> yandex (32) - client_id> [вставить CLIENT_ID] - client_secret> [вставить CLIENT_SECRET] - token> [вставить токен из authorize] **Теория:** OAuth-токен даёт доступ к Яндекс.Диску. Хранится в `~/.config/rclone/rclone.conf`. Права на файл должны быть 600. ## 5. Systemd Credentials (шифрование секретов) ### Создание файла с секретами ```bash cat > /tmp/backup.creds <<'EOF' nc.url=https://nc.zailon.ru nc.user=hermes nc.pass=EfyyJ-9E4L2-KH53k-8GsGe-dqysA nc.path.logs=transit/Charon-vpn/Logs nc.path.vpn=transit/Charon-vpn/OlimpVPN EOF ``` ### Шифрование через systemd-creds ```bash systemd-creds --name=backup.creds encrypt /tmp/backup.creds /etc/backup/backup.creds chmod 600 /etc/backup/backup.creds shred -u /tmp/backup.creds ``` **Теория:** `systemd-creds` шифрует файл с секретами. Расшифровка происходит автоматически при запуске сервиса через `LoadCredentialEncrypted`. Файл доступен только во время работы сервиса в `/run/credentials//backup.creds`. ## 6. Скрипты бэкапов ### logs-backup.sh (инкрементные бэкапы) ```bash cat > /opt/backup/logs-backup.sh <<'SCRIPT' #!/bin/bash set -euo pipefail CREDS="${CREDENTIALS_DIRECTORY}/backup.creds" NC_URL="$(grep '^nc.url=' "$CREDS" | cut -d= -f2-)" NC_USER="$(grep '^nc.user=' "$CREDS" | cut -d= -f2-)" NC_PASS="$(grep '^nc.pass=' "$CREDS" | cut -d= -f2-)" NC_PATH_LOGS="$(grep '^nc.path.logs=' "$CREDS" | cut -d= -f2-)" BACKUP_DIR="/opt/backup" DATE_SHORT=$(date +%Y%m%d) HOSTNAME="Charon-vpn" LOG_FILE="/var/log/logs-backup.log" AUTH_LOG="/var/log/auth.log" OFFSET_FILE="${BACKUP_DIR}/.auth_offset" INODE_FILE="${BACKUP_DIR}/.auth_inode" YANDEX_REMOTE="yandex" YANDEX_PATH="Olimp/Logs/${HOSTNAME}" LOGS_BACKUP="${HOSTNAME}_ssh_inc_${DATE_SHORT}.tar.gz" AUDIT_BACKUP="${HOSTNAME}_audit_${DATE_SHORT}.tar.gz" CURRENT_INODE=$(stat -c%i "$AUTH_LOG" 2>/dev/null || echo 0) LAST_INODE=$([ -f "$INODE_FILE" ] && cat "$INODE_FILE" || echo 0) if [ "$CURRENT_INODE" != "$LAST_INODE" ]; then echo "0" > "$OFFSET_FILE" echo "$CURRENT_INODE" > "$INODE_FILE" fi log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "${LOG_FILE}"; } mkdir -p "${BACKUP_DIR}" log "=== Начало бэкапа логов ===" log "Инкрементальный бэкап SSH-логов..." TMP_LOG=$(mktemp -d) LAST_OFFSET=$([ -f "$OFFSET_FILE" ] && cat "$OFFSET_FILE" || echo 0) CURRENT_SIZE=$(stat -c%s "$AUTH_LOG" 2>/dev/null || echo 0) if [ "$CURRENT_SIZE" -gt "$LAST_OFFSET" ]; then tail -c +$((LAST_OFFSET + 1)) "$AUTH_LOG" > "${TMP_LOG}/ssh_inc_${DATE_SHORT}.log" NEW_SIZE=$(stat -c%s "${TMP_LOG}/ssh_inc_${DATE_SHORT}.log") log "Новых записей: ${NEW_SIZE} байт (offset: ${LAST_OFFSET} → ${CURRENT_SIZE})" else echo "No new SSH events" > "${TMP_LOG}/ssh_inc_${DATE_SHORT}.log" log "Нет новых записей" fi echo "$CURRENT_SIZE" > "$OFFSET_FILE" tar -czf "${BACKUP_DIR}/${LOGS_BACKUP}" -C "${TMP_LOG}" . rm -rf "${TMP_LOG}" log "Архив логов: $(du -h ${BACKUP_DIR}/${LOGS_BACKUP} | cut -f1)" log "Сбор аудита системы..." AUDIT_TMP=$(mktemp -d) cp ~/.bash_history "${AUDIT_TMP}/history.txt" 2>/dev/null || true dpkg -l > "${AUDIT_TMP}/packages.txt" 2>/dev/null || true ps auxf > "${AUDIT_TMP}/processes.txt" ss -tlnp > "${AUDIT_TMP}/network_listen.txt" ss -anp > "${AUDIT_TMP}/network_all.txt" crontab -l > "${AUDIT_TMP}/cron.txt" 2>/dev/null || true cat /etc/passwd > "${AUDIT_TMP}/users.txt" awk -F: '$3==0' /etc/passwd > "${AUDIT_TMP}/uid0_users.txt" cat ~/.ssh/authorized_keys > "${AUDIT_TMP}/ssh_keys.txt" 2>/dev/null || true systemctl list-units --type=service --state=running > "${AUDIT_TMP}/services.txt" 2>/dev/null || true tar -czf "${BACKUP_DIR}/${AUDIT_BACKUP}" -C "${AUDIT_TMP}" . rm -rf "${AUDIT_TMP}" log "Архив аудита: $(du -h ${BACKUP_DIR}/${AUDIT_BACKUP} | cut -f1)" log "Загрузка на Nextcloud (transit/Charon-vpn/Logs)..." for file in "${LOGS_BACKUP}" "${AUDIT_BACKUP}"; do curl -T "${BACKUP_DIR}/${file}" -u "${NC_USER}:${NC_PASS}" \ "${NC_URL}/remote.php/dav/files/${NC_USER}/${NC_PATH_LOGS}/${file}" \ --silent --show-error --fail 2>&1 | tee -a "${LOG_FILE}" || log "WARN: Nextcloud ${file}" done log "✓ Nextcloud загружен (transit/Charon-vpn/Logs)" log "Загрузка на Яндекс Диск (${YANDEX_PATH})..." rclone mkdir "${YANDEX_REMOTE}:${YANDEX_PATH}" 2>/dev/null || true for file in "${LOGS_BACKUP}" "${AUDIT_BACKUP}"; do rclone copy "${BACKUP_DIR}/${file}" "${YANDEX_REMOTE}:${YANDEX_PATH}/" 2>&1 | tee -a "${LOG_FILE}" || log "WARN: Yandex ${file}" done log "✓ Яндекс Диск загружен" log "Ротация локальных файлов (>30 дней)..." find "${BACKUP_DIR}" -name "${HOSTNAME}_ssh_inc_*.tar.gz" -mtime +30 -delete find "${BACKUP_DIR}" -name "${HOSTNAME}_audit_*.tar.gz" -mtime +30 -delete log "Ротация на Яндекс Диске (>30 дней)..." rclone delete "${YANDEX_REMOTE}:${YANDEX_PATH}" --min-age 30d 2>&1 | tee -a "${LOG_FILE}" || log "WARN: Yandex rotation" log "=== Бэкап логов завершён ===" SCRIPT chmod +x /opt/backup/logs-backup.sh ``` **Теория:** Скрипт использует инкрементальный бэкап — сохраняет только новые записи auth.log с момента последнего запуска. Отслеживает inode файла для обнаружения ротации logrotate. Собирает аудит системы (установленные пакеты, процессы, сетевые соединения, cron, пользователи). ### logs-full-backup.sh (полный бэкап раз в неделю) ```bash cat > /opt/backup/logs-full-backup.sh <<'SCRIPT' #!/bin/bash set -euo pipefail CREDS="${CREDENTIALS_DIRECTORY}/backup.creds" NC_URL="$(grep '^nc.url=' "$CREDS" | cut -d= -f2-)" NC_USER="$(grep '^nc.user=' "$CREDS" | cut -d= -f2-)" NC_PASS="$(grep '^nc.pass=' "$CREDS" | cut -d= -f2-)" NC_PATH_LOGS="$(grep '^nc.path.logs=' "$CREDS" | cut -d= -f2-)" BACKUP_DIR="/opt/backup" DATE_SHORT=$(date +%Y%m%d) HOSTNAME="Charon-vpn" LOG_FILE="/var/log/logs-backup.log" YANDEX_REMOTE="yandex" YANDEX_PATH="Olimp/Logs/${HOSTNAME}" FULL_BACKUP="${HOSTNAME}_logs_full_${DATE_SHORT}.tar.gz" log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "${LOG_FILE}"; } mkdir -p "${BACKUP_DIR}" log "=== Начало полного бэкапа логов ===" log "Создание полного архива логов..." TMP_LOG=$(mktemp -d) cp /var/log/auth.log "${TMP_LOG}/" 2>/dev/null || true cp /var/log/auth.log.* "${TMP_LOG}/" 2>/dev/null || true tar -czf "${BACKUP_DIR}/${FULL_BACKUP}" -C "${TMP_LOG}" . rm -rf "${TMP_LOG}" log "Полный архив логов: $(du -h ${BACKUP_DIR}/${FULL_BACKUP} | cut -f1)" log "Загрузка на Nextcloud (transit/Charon-vpn/Logs)..." curl -T "${BACKUP_DIR}/${FULL_BACKUP}" -u "${NC_USER}:${NC_PASS}" \ "${NC_URL}/remote.php/dav/files/${NC_USER}/${NC_PATH_LOGS}/${FULL_BACKUP}" \ --silent --show-error --fail 2>&1 | tee -a "${LOG_FILE}" || log "WARN: Nextcloud ${FULL_BACKUP}" log "✓ Nextcloud загружен (transit/Charon-vpn/Logs)" log "Загрузка на Яндекс Диск..." rclone copy "${BACKUP_DIR}/${FULL_BACKUP}" "${YANDEX_REMOTE}:${YANDEX_PATH}/" 2>&1 | tee -a "${LOG_FILE}" || log "WARN: Yandex ${FULL_BACKUP}" log "✓ Яндекс Диск загружен" log "Ротация старых файлов (>30 дней)..." find "${BACKUP_DIR}" -name "${HOSTNAME}_logs_full_*.tar.gz" -mtime +30 -delete log "=== Полный бэкап логов завершён ===" SCRIPT chmod +x /opt/backup/logs-full-backup.sh ``` **Теория:** Создаёт полный архив всех логов auth.log и ротированных файлов. Запускается раз в неделю в воскресенье. ### backup.sh (бэкап 3x-ui) ```bash cat > /opt/3x-ui/backup.sh <<'SCRIPT' #!/bin/bash set -euo pipefail CREDS="${CREDENTIALS_DIRECTORY}/backup.creds" NC_URL="$(grep '^nc.url=' "$CREDS" | cut -d= -f2-)" NC_USER="$(grep '^nc.user=' "$CREDS" | cut -d= -f2-)" NC_PASS="$(grep '^nc.pass=' "$CREDS" | cut -d= -f2-)" NC_PATH_VPN="$(grep '^nc.path.vpn=' "$CREDS" | cut -d= -f2-)" BACKUP_DIR="/opt/3x-ui/backups" DATE=$(date +%Y%m%d_%H%M%S) HOSTNAME="Charon-vpn" LOG_FILE="/var/log/3x-ui-backup.log" YANDEX_REMOTE="yandex" YANDEX_PATH="Olimp/VPN/${HOSTNAME}" VPN_BACKUP="${HOSTNAME}_3xui_${DATE}.tar.gz" log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "${LOG_FILE}"; } mkdir -p "${BACKUP_DIR}" log "=== Начало бэкапа 3x-ui ===" log "Создание архива 3x-ui..." tar -czf "${BACKUP_DIR}/${VPN_BACKUP}" -C /opt/3x-ui db cert docker-compose.yml 2>/dev/null || { log "ERROR: не удалось создать архив 3x-ui" exit 1 } log "Архив 3x-ui: $(du -h ${BACKUP_DIR}/${VPN_BACKUP} | cut -f1)" log "Загрузка 3x-ui на Nextcloud (transit/Charon-vpn/OlimpVPN)..." curl -T "${BACKUP_DIR}/${VPN_BACKUP}" -u "${NC_USER}:${NC_PASS}" \ "${NC_URL}/remote.php/dav/files/${NC_USER}/${NC_PATH_VPN}/${VPN_BACKUP}" \ --silent --show-error --fail 2>&1 | tee -a "${LOG_FILE}" || { log "ERROR: загрузка 3x-ui на Nextcloud" exit 1 } log "✓ Nextcloud загружен (transit/Charon-vpn/OlimpVPN)" log "Загрузка на Яндекс Диск (${YANDEX_PATH})..." rclone mkdir "${YANDEX_REMOTE}:${YANDEX_PATH}" 2>/dev/null || true rclone copy "${BACKUP_DIR}/${VPN_BACKUP}" "${YANDEX_REMOTE}:${YANDEX_PATH}/" 2>&1 | tee -a "${LOG_FILE}" || log "WARN: Yandex ${VPN_BACKUP}" log "✓ Яндекс Диск загружен" log "Ротация локальных файлов (>30 дней)..." find "${BACKUP_DIR}" -name "${HOSTNAME}_3xui_*.tar.gz" -mtime +30 -delete log "Ротация на Яндекс Диске (>30 дней)..." rclone delete "${YANDEX_REMOTE}:${YANDEX_PATH}" --min-age 30d 2>&1 | tee -a "${LOG_FILE}" || log "WARN: Yandex rotation" log "=== Бэкап 3x-ui завершён ===" SCRIPT chmod +x /opt/3x-ui/backup.sh ``` **Теория:** Бэкапит конфигурацию 3x-ui (база данных, сертификаты, docker-compose.yml). Запускается раз в 3 дня. ## 7. Systemd Units и Timers ### logs-backup.service ```ini [Unit] Description=Daily logs and audit backup to Nextcloud and Yandex After=network-online.target Wants=network-online.target [Service] Type=oneshot LoadCredentialEncrypted=backup.creds:/etc/backup/backup.creds ExecStart=/opt/backup/logs-backup.sh StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target ``` ### logs-backup.timer ```ini [Unit] Description=Run incremental logs backup Mon-Sat at 03:00 [Timer] OnCalendar=Mon..Sat *-*-* 03:00:00 Persistent=true RandomizedDelaySec=1h [Install] WantedBy=timers.target ``` ### logs-full-backup.service ```ini [Unit] Description=Weekly full logs backup to Nextcloud and Yandex After=network-online.target Wants=network-online.target [Service] Type=oneshot LoadCredentialEncrypted=backup.creds:/etc/backup/backup.creds ExecStart=/opt/backup/logs-full-backup.sh StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target ``` ### logs-full-backup.timer ```ini [Unit] Description=Run full logs backup weekly on Sunday at 04:00 [Timer] OnCalendar=Sun *-*-* 04:00:00 Persistent=true [Install] WantedBy=timers.target ``` ### xui-backup.service ```ini [Unit] Description=3x-ui backup to Nextcloud and Yandex After=network-online.target Wants=network-online.target [Service] Type=oneshot LoadCredentialEncrypted=backup.creds:/etc/backup/backup.creds ExecStart=/opt/3x-ui/backup.sh StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target ``` ### xui-backup.timer ```ini [Unit] Description=Run 3x-ui backup every 3 days at 04:00 [Timer] OnCalendar=*-*-* 04:00:00 Persistent=true RandomizedDelaySec=2h [Install] WantedBy=timers.target ``` **Теория:** `LoadCredentialEncrypted` автоматически расшифровывает credentials при запуске сервиса. `Persistent=true` гарантирует, что пропущенные запуски будут выполнены при следующей возможности. `RandomizedDelaySec` добавляет случайную задержку, чтобы избежать одновременного запуска на множестве серверов. ### Активация timers ```bash systemctl daemon-reload systemctl enable --now logs-backup.timer systemctl enable --now logs-full-backup.timer systemctl enable --now xui-backup.timer ``` ## 8. Автоматизация на Nextcloud ### nextcloud-transit-processor.sh ```bash cat > /usr/local/bin/nextcloud-transit-processor.sh <<'EOF' #!/bin/bash PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin NEXTCLOUD_PATH="/var/www/nextcloud" DATA_PATH="/mnt/cloud/data" TRANSIT_PATH="$DATA_PATH/hermes/files/transit" FINAL_PATH="$DATA_PATH/Zailon/files/Admin/Olimp/OlimpBackup" LOG_FILE="/var/log/nextcloud-transit.log" log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE" } if [ ! -d "$TRANSIT_PATH" ]; then log "ERROR: Папка transit не найдена: $TRANSIT_PATH" exit 1 fi for host_dir in "$TRANSIT_PATH"/*/; do [ -d "$host_dir" ] || continue hostname=$(basename "$host_dir") log "Обнаружен хост: $hostname" for category_dir in "$host_dir"*/; do [ -d "$category_dir" ] || continue category=$(basename "$category_dir") target_dir="$FINAL_PATH/$hostname/$category" if [ ! -d "$target_dir" ]; then mkdir -p "$target_dir" chown -R www-data:www-data "$target_dir" log "Создана папка: $target_dir" fi file_count=0 for file in "$category_dir"*; do if [ -f "$file" ]; then filename=$(basename "$file") mv "$file" "$target_dir/" log "Перемещён: $hostname/$category/$filename" file_count=$((file_count + 1)) fi done if [ "$file_count" -gt 0 ]; then log "Перемещено файлов: $file_count из $hostname/$category" fi done done log "Обновление индекса Nextcloud..." /usr/bin/php "$NEXTCLOUD_PATH/occ" files:scan --path="hermes/files/transit" >> "$LOG_FILE" 2>&1 /usr/bin/php "$NEXTCLOUD_PATH/occ" files:scan --path="Zailon/files/Admin/Olimp/OlimpBackup/" >> "$LOG_FILE" 2>&1 log "Индекс обновлён" log "=== Обработка завершена ===" EOF chmod +x /usr/local/bin/nextcloud-transit-processor.sh chown www-data:www-data /usr/local/bin/nextcloud-transit-processor.sh ``` ### Добавление в cron ```bash touch /var/log/nextcloud-transit.log chown www-data:www-data /var/log/nextcloud-transit.log chmod 644 /var/log/nextcloud-transit.log (crontab -u www-data -l 2>/dev/null; echo "* * * * * /usr/local/bin/nextcloud-transit-processor.sh") | crontab -u www-data - ``` **Теория:** Скрипт запускается каждую минуту, автоматически обнаруживает новые хосты и категории в transit, перемещает файлы в финальные папки. Универсальный — не требует изменений при добавлении новых VPS или сервисов. ## 9. Расписание и ротация | Сервис | Расписание | Nextcloud | Яндекс Диск | |--------|------------|-----------|-------------| | logs-backup (инкремент) | Пн-Сб 03:37 | transit/Charon-vpn/Logs | Olimp/Logs/Charon-vpn | | logs-full-backup (полный) | Вс 04:00 | transit/Charon-vpn/Logs | Olimp/Logs/Charon-vpn | | xui-backup (3x-ui) | Раз в 3 дня 05:31 | transit/Charon-vpn/OlimpVPN | Olimp/VPN/Charon-vpn | **Ротация:** 30 дней для всех файлов (локально и на Яндекс Диске). ## 10. Безопасность ### Защита от компрометации VPS Если злоумышленник получит root на VPS: - Увидит credentials hermes (App Password) - Сможет загружать файлы в transit - **Не сможет** удалить файлы (hermes не имеет прав на удаление в финальных папках) - **Не сможет** прочитать файлы других пользователей - **Не знает** про структуру финального хранилища ### Изоляция через transit Поток данных: 1. VPS загружает файлы в `transit/{hostname}/{category}/` 2. Cron на Nextcloud перемещает файлы в `Admin/Olimp/OlimpBackup/{hostname}/{category}/` 3. Файлы в transit удаляются автоматически Даже если VPS скомпрометирован, злоумышленник видит только пустую папку transit. ### Шифрование credentials Все секреты хранятся в зашифрованном виде через `systemd-creds`. Расшифровка происходит только во время работы сервиса. ## 11. Мониторинг и проверка ### Проверка работы timers ```bash systemctl list-timers --all | grep -E 'logs-backup|logs-full|xui-backup' ``` ### Проверка логов ```bash journalctl -u logs-backup -n 30 journalctl -u logs-full-backup -n 30 journalctl -u xui-backup -n 30 ``` ### Проверка файлов на Яндекс Диске ```bash rclone ls yandex:Olimp/Logs/Charon-vpn/ rclone ls yandex:Olimp/VPN/Charon-vpn/ ``` ### Проверка transit на Nextcloud ```bash find /mnt/cloud/data/hermes/files/transit/ -type f ``` Должно быть пусто (файлы автоматически перемещаются). ### Проверка финальных папок ```bash ls -la /mnt/cloud/data/Zailon/files/Admin/Olimp/OlimpBackup/Charon-vpn/Logs/ ls -la /mnt/cloud/data/Zailon/files/Admin/Olimp/OlimpBackup/Charon-vpn/OlimpVPN/ ``` ## 12. Добавление нового VPS ### На новом сервере 1. Создать credentials: ```bash cat > /tmp/backup.creds <<'EOF' nc.url=https://nc.zailon.ru nc.user=hermes nc.pass=EfyyJ-9E4L2-KH53k-8GsGe-dqysA nc.path.logs=transit/NewVPS/Logs nc.path.vpn=transit/NewVPS/OlimpVPN EOF systemd-creds --name=backup.creds encrypt /tmp/backup.creds /etc/backup/backup.creds chmod 600 /etc/backup/backup.creds shred -u /tmp/backup.creds ``` 2. Скопировать скрипты: ```bash scp /opt/backup/logs-backup.sh root@new-vps:/opt/backup/ scp /opt/backup/logs-full-backup.sh root@new-vps:/opt/backup/ scp /opt/3x-ui/backup.sh root@new-vps:/opt/3x-ui/ ``` 3. Обновить HOSTNAME в скриптах: ```bash sed -i 's/HOSTNAME="Charon-vpn"/HOSTNAME="NewVPS"/' /opt/backup/logs-backup.sh sed -i 's/HOSTNAME="Charon-vpn"/HOSTNAME="NewVPS"/' /opt/backup/logs-full-backup.sh sed -i 's/HOSTNAME="Charon-vpn"/HOSTNAME="NewVPS"/' /opt/3x-ui/backup.sh ``` 4. Настроить systemd units и timers (аналогично Charon-vpn) 5. На сервере Nextcloud создать папки: ```bash mkdir -p /mnt/cloud/data/hermes/files/transit/NewVPS/Logs mkdir -p /mnt/cloud/data/hermes/files/transit/NewVPS/OlimpVPN chown -R www-data:www-data /mnt/cloud/data/hermes/files/transit/NewVPS/ sudo -u www-data php /var/www/nextcloud/occ files:scan hermes ``` **Теория:** Скрипт nextcloud-transit-processor.sh автоматически обнаружит новый хост и начнёт перемещать файлы. Никаких изменений в скрипте не требуется. ## 13. Очистка истории и запуск мониторинга ### Сброс offset для инкрементных бэкапов ```bash echo "0" > /opt/backup/.auth_offset > /opt/backup/.auth_inode ``` ### Очистка bash history ```bash history -c > ~/.bash_history history -w unset HISTFILE ``` ### Ротация auth.log ```bash logrotate -f /etc/logrotate.conf ``` ### Очистка старых локальных бэкапов ```bash rm -f /opt/backup/Charon-vpn_*.tar.gz rm -f /opt/3x-ui/backups/Charon-vpn_*.tar.gz ``` ### Очистка логов бэкапов ```bash > /var/log/logs-backup.log > /var/log/3x-ui-backup.log ``` ### Тестовый запуск ```bash systemctl start logs-backup.service systemctl start logs-full-backup.service systemctl start xui-backup.service ``` ### Проверка ```bash journalctl -u logs-backup -n 20 journalctl -u logs-full-backup -n 20 journalctl -u xui-backup -n 20 ``` ## 14. Итоговый статус системы | Компонент | Статус | |-----------|--------| | SSH порт 45132 | ✅ Работает | | PasswordAuthentication | ✅ Отключён | | CrowdSec | ✅ Работает | | Бэкап 3x-ui | ✅ Раз в 3 дня | | Инкрементные бэкапы логов | ✅ Пн-Сб 03:37 | | Полные бэкапы логов | ✅ Вс 04:00 | | Nextcloud (transit) | ✅ Автоматическое перемещение | | Яндекс Диск | ✅ Прямая загрузка | | Аудит системы | ✅ Ежедневный снэпшот | | Ротация 30 дней | ✅ Автоматически | | Отслеживание ротации auth.log | ✅ Через inode | | Credentials зашифрованы | ✅ systemd-creds | | Rclone конфиг | ✅ Права 600 | | Универсальность | ✅ Новые хосты без изменений | ## 15. Дальнейшее развитие ### Алерты об успешных входах не из белого списка Можно настроить через cron, который каждую минуту проверяет auth.log на новые успешные входы и отправляет алерты на Nextcloud/Telegram. ### Google Drive как третье хранилище Добавить через `rclone authorize "drive"` для дополнительной отказоустойчивости. ### Шифрование бэкапов через rclone crypt Создать encrypted remote поверх yandex: для защиты содержимого файлов даже при компрометации OAuth-токена.