diff --git a/README.md b/README.md index 494df03..c766374 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,157 @@ -# backup-manager +# OpenWrt Backup Manager +Автономный набор скриптов для бэкапа и восстановления конфигурации и пакетов на OpenWrt. + +## Возможности + +#### Бэкап + +- системных конфигов +- пользовательских файлов +- списка установленных пакетов (apk) + +#### Восстановление + +- конфигурации через sysupgrade +- пакетов из сохранённого списка + +#### Поддержка удалённого хранилища + +- NFS +- SMB (CIFS) + +#### Очистка старых бэкапов (локально и удалённо) + +## Структура + +```bash +. +├── backup-manager.sh # основной скрипт +├── backup-configs.sh # сбор конфигураций +├── backup-apk.sh # работа с пакетами +├── README.md +``` + +## Настройка + +Отредактируйте переменные в backup-manager.sh: + +### Хранилище + +```bash +STORAGE_TYPE="nfs" # nfs или smb +S_HOST="nfs.lan" +S_PATH="/mnt/media1/backup" +``` + +### Для SMB + +```bash +SMB_USER="guest" +SMB_PASS="guest" +``` + +### Политика хранения + +```bash +LOCAL_KEEP=10 # сколько хранить локально +HOST_KEEP=30 # сколько дней хранить удалённо +``` + +### Что бэкапить + +```bash +C_LIST=" +/etc/config +/etc/xray +/root/.ssh +... +" +``` + +### Что исключить + +```bash +C_EXCLUDE=" +/opt/.backup-manager/local_backups +/etc/xray/ipset +" +``` + +### Конфликтующие пакеты + +Удаляются перед восстановлением: + +```bash +H_REPLACE="wpad dnsmasq" +``` + +## Использование + +### Создать бэкап + +```bash +./backup-manager.sh backup +``` + +#### Что происходит: + +- создаётся архив .tar.gz +- сохраняется список пакетов .lst +- копируется на удалённое хранилище (если доступно) + +### Восстановление + +```bash +./backup-manager.sh restore +``` + +#### Далее интерактивно: + +1. Выбор источника (локальный / удалённый) +2. Выбор типа: + - конфигурация + - пакеты + +## Как работает бэкап пакетов + +#### Скрипт: + +- определяет пакеты, установленные пользователем +- исключает зависимости + + +## Зависимости + +#### Для NFS + +```sh +opkg install kmod-fs-nfs kmod-fs-nfs-v3 kmod-fs-nfs-v4 nfs-utils +``` + +#### Для SMB +```sh +opkg install kmod-fs-cifs cifs-utils +``` + +## Особенности +- Используется временная директория: /tmp +- При восстановлении пакетов: + - временно правится DNS (Cloudflare) +- Для восстановления конфигурации используется: +```sh +sysupgrade -r backup.tar.gz +``` + +## Очистка + +#### Автоматически: +- старые локальные бэкапы +- удалённые файлы старше HOST_KEEP дней + + +## Пример cron + +```sh +0 3 * * * /opt/.backup-manager/backup-manager.sh backup +``` \ No newline at end of file diff --git a/backup-opkg.sh b/backup-apk.sh similarity index 60% rename from backup-opkg.sh rename to backup-apk.sh index 5e8e5b5..d6946d9 100755 --- a/backup-opkg.sh +++ b/backup-apk.sh @@ -6,8 +6,6 @@ H_REPLACE="$3" [ -z "$CMD" ] || [ -z "$LOCAL_LST" ] || [ -z "$H_REPLACE" ] && echo "Missing params!" && exit 1 -TMP_DIR="/tmp/opkg_restore" - fix_dns() { local dns1="1.1.1.1" local dns2="1.0.0.1" @@ -20,28 +18,11 @@ fix_dns() { } list_user_packages() { - awk -f - << 'EOF' -BEGIN { - status_file = "/usr/lib/opkg/status" - cmd="opkg info busybox | grep '^Installed-Time: '" - if ((cmd | getline line) > 0) { - FLASH_TIME = substr(line, 17) - } - close(cmd) - while ((getline < status_file) > 0) { - if ($1 == "Package:") { pkg = $2 } - if ($1 == "Installed-Time:") { - installed_time = $2 - if (installed_time > FLASH_TIME) { - check_cmd = "opkg whatdepends " pkg " | wc -l" - check_cmd | getline whatdepends - close(check_cmd) - if (whatdepends == 3) print pkg - } - } - } -} -EOF + if [ -f /rom/etc/apk/world ]; then + grep -v -F -x -f /rom/etc/apk/world /etc/apk/world | sed 's/=.*//' + else + cat /etc/apk/world | sed 's/=.*//' + fi } case "$CMD" in @@ -61,34 +42,38 @@ case "$CMD" in [ ! -f /etc/resolv.conf-backup ] && cp /etc/resolv.conf /etc/resolv.conf-backup fix_dns printf "Updating package lists... " - opkg update >/dev/null 2>&1 + apk update >/dev/null 2>&1 echo "OK" + echo "Removing conflicts:" if [ -n "$H_REPLACE" ]; then - REMOVABLE=$(opkg list-installed | grep -E $(echo "$H_REPLACE" | tr ' ' '|') | awk '{print $1}') + local pattern=$(echo "$H_REPLACE" | sed 's/ /|/g') + REMOVABLE=$(apk list --installed | grep -E "$pattern" | awk '{print $1}' | sed 's/-[0-9].*$//') for p in $REMOVABLE; do printf " [-] %s... " "$p" - opkg remove "$p" --force-depends >/dev/null 2>&1 + apk del "$p" >/dev/null 2>&1 echo "OK" done fi + echo "Installing packages:" for pkg in $(cat "$LOCAL_LST"); do - if opkg list-installed | grep -q "^$pkg "; then + if apk info -e "$pkg" >/dev/null 2>&1; then echo " [s] $pkg... is already installed" else fix_dns printf " [+] $pkg... " - if opkg install "$pkg" >/dev/null 2>&1; then + if apk add "$pkg" >/dev/null 2>&1; then echo "OK" else echo "FAILED" fi fi done + [ -f /etc/resolv.conf-backup ] && mv /etc/resolv.conf-backup /etc/resolv.conf echo "Summary:" - echo " Restore complete." - echo " Reboot is recommended." + echo " Restore complete" + echo " Reboot is recommended" ;; -esac +esac \ No newline at end of file diff --git a/backup-configs.sh b/backup-configs.sh index 9a2ab84..2b446fa 100755 --- a/backup-configs.sh +++ b/backup-configs.sh @@ -2,7 +2,7 @@ LOCAL_FILE="$1" LOCAL_LST="$2" -SCR_OPKG="$3" +SCR_APK="$3" C_LIST="$4" H_REPLACE="$5" C_EXCLUDE="$6" @@ -12,7 +12,7 @@ C_EXCLUDE="$6" TMP_DIR="/tmp/backup_stack" rm -rf "$TMP_DIR" && mkdir -p "$TMP_DIR" -$SCR_OPKG write "$LOCAL_LST" "$H_REPLACE" +$SCR_APK write "$LOCAL_LST" "$H_REPLACE" echo "Included:" for p in $C_LIST; do diff --git a/backup-manager.sh b/backup-manager.sh index bb208bb..f3a0b4b 100755 --- a/backup-manager.sh +++ b/backup-manager.sh @@ -28,17 +28,17 @@ C_LIST=" /opt/.xray-config /opt/.backup-manager /etc/nftables.d/10-netmap.nft +/etc/nftables.d/15-pbr-mark.nft /etc/hotplug.d/iface/99-xray-restart /etc/zabbix_agentd.conf /etc/dropbear /etc/banner /etc/init.d/xray +/etc/crontabs/root " C_EXCLUDE=" /opt/.backup-manager/local_backups -/etc/xray/ipset -/etc/xray/ipnet " H_REPLACE="wpad dnsmasq" @@ -47,7 +47,7 @@ DIR=$(cd "$(dirname "$0")" && pwd) #DIR="/opt/.backup-manager" L_BACKUP_DIR="$DIR/local_backups" SCR_BACKUP="$DIR/backup-configs.sh" -SCR_OPKG="$DIR/backup-opkg.sh" +SCR_APK="$DIR/backup-apk.sh" mkdir -p "$L_BACKUP_DIR" @@ -73,11 +73,16 @@ check_dependencies() { local pkgs="" [ "$STORAGE_TYPE" = "nfs" ] && pkgs="kmod-fs-nfs kmod-fs-nfs-v3 kmod-fs-nfs-v4 nfs-utils" [ "$STORAGE_TYPE" = "smb" ] && pkgs="kmod-fs-cifs cifs-utils" + local missing="" for pkg in $pkgs; do - opkg list-installed | grep -q "^$pkg " || missing="$missing $pkg" + if ! apk info -e "$pkg" >/dev/null 2>&1; then + missing="$missing $pkg" + fi done + if [ -n "$missing" ]; then + echo "FAILED" echo " [!] Missing: $missing. Install them to use remote backup." return 1 fi @@ -144,7 +149,7 @@ case "$1" in LOCAL_FILE="$L_BACKUP_DIR/backup_${HNAME}_${DATE}.tar.gz" LOCAL_LST="$L_BACKUP_DIR/packages_${HNAME}_${DATE}.lst" REMOTE_STATUS="FAILED" - $SCR_BACKUP "$LOCAL_FILE" "$LOCAL_LST" "$SCR_OPKG" "$C_LIST" "$H_REPLACE" "$C_EXCLUDE" + $SCR_BACKUP "$LOCAL_FILE" "$LOCAL_LST" "$SCR_APK" "$C_LIST" "$H_REPLACE" "$C_EXCLUDE" manage_local_backups if check_network && check_dependencies && mount_share; then printf "Copying to %s storage... " "$STORAGE_TYPE" @@ -198,7 +203,7 @@ case "$1" in 2) select_file "$R_DIR" ".lst" if [ -n "$SELECTED_PATH" ]; then - $SCR_OPKG restore "$SELECTED_PATH" "$H_REPLACE" + $SCR_APK restore "$SELECTED_PATH" "$H_REPLACE" fi ;; *)