Полнота бэкапа: SSH, весь UFW, свои юниты, конфиги пакетов, системные параметры
CI / test (push) Successful in 1m27s
Release / release (push) Successful in 1m26s

Агент:
- ssh: sshd_config(.d), ключи хоста, authorized_keys root и пользователей
- system: весь /etc/ufw и /etc/default/ufw, /etc/sysctl.conf, /etc/hosts,
  свои файлы в /etc/cron.d (пакетные отсекаются через dpkg -S)
- certs: /etc/letsencrypt, /root/.acme.sh; xui: сертификаты по путям из базы
- docker: daemon.json и логины в registry; telegraf: /etc/default/telegraf
- caddy: бинарник бэкапится, если Caddy собран с плагинами
- units: свои systemd-юниты с состоянием enabled/active и drop-in *.service.d
- etc: изменённые конфиги любых пакетов (dpkg conffiles) и свои файлы в /etc,
  кроме привязанного к железу и облаку
- в манифесте: часовой пояс, swap, вручную поставленные пакеты; версия
  apt-пакета в строке категории
- предупреждения: программы юнитов вне бэкапа, каталоги /opt и /usr/local/bin
  без категории, контейнеры без compose

Restore:
- часовой пояс, swap-файл, доустановка вручную поставленных пакетов
- свои юниты включаются и запускаются как на старом сервере

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mrleo1nidandClaude Opus 5.5 committed 2026-10-17 15:19:34 +03:00
1 parent cbd3cde01d
commit 1947b26913
14 files changed
+747 -45

No files matched your search

+19 -9
View File
@@ -17,6 +17,8 @@ const (
TypeSystemd = "systemd"
TypeXUI = "xui"
TypeCompose = "compose"
// TypeUnits — свои systemd-юниты (не из пакетов) с состоянием enabled/active.
TypeUnits = "units"
)
type Config struct {
@@ -33,15 +35,23 @@ type Spec struct {
Detect []string `yaml:"detect,omitempty"` // категория активна, если существует хоть один путь
Paths []string `yaml:"paths,omitempty"`
Exclude []string `yaml:"exclude,omitempty"`
// Unowned — маски файлов, которые берутся, только если они не принадлежат
// ни одному пакету (dpkg -S): свои файлы в /etc/cron.d, /etc/systemd/system и т.п.
Unowned []string `yaml:"unowned,omitempty"`
// ModifiedConffiles — добавить конфиги пакетов, изменённые относительно поставки.
ModifiedConffiles bool `yaml:"modified_conffiles,omitempty"`
Service string `yaml:"service,omitempty"`
VersionCmd []string `yaml:"version_cmd,omitempty"`
VersionRegex string `yaml:"version_regex,omitempty"`
Install string `yaml:"install,omitempty"` // recipe: nebula, xui, sing-box-extended
KeepBinaries []string `yaml:"keep_binaries,omitempty"` // fallback-копии бинарников
EnsureDirs []string `yaml:"ensure_dirs,omitempty"`
PostRestore []string `yaml:"post_restore,omitempty"`
Dumps []CmdDump `yaml:"dumps,omitempty"`
Service string `yaml:"service,omitempty"`
VersionCmd []string `yaml:"version_cmd,omitempty"`
VersionRegex string `yaml:"version_regex,omitempty"`
Install string `yaml:"install,omitempty"` // recipe: nebula, xui, sing-box-extended
KeepBinaries []string `yaml:"keep_binaries,omitempty"` // fallback-копии бинарников
// KeepBinariesIf — shell-условие: keep_binaries берутся, только если оно истинно
// (например, Caddy собран с плагинами и из apt его не вернуть).
KeepBinariesIf string `yaml:"keep_binaries_if,omitempty"`
EnsureDirs []string `yaml:"ensure_dirs,omitempty"`
PostRestore []string `yaml:"post_restore,omitempty"`
Dumps []CmdDump `yaml:"dumps,omitempty"`
// compose
Dir string `yaml:"dir,omitempty"`
@@ -127,7 +137,7 @@ func (c *Config) Validate() error {
continue
}
switch s.Type {
case TypeFiles, TypeSystemd, TypeXUI:
case TypeFiles, TypeSystemd, TypeXUI, TypeUnits:
case TypeCompose:
if s.Dir == "" && s.Project == "" {
return fmt.Errorf("категория %q: для compose нужен dir или project", s.Name)
+80 -5
View File
@@ -10,16 +10,38 @@ categories:
- name: system
type: files
paths:
- /etc/ufw/user.rules
- /etc/ufw/user6.rules
- /var/spool/cron/crontabs
- /etc/cron.d/ban-blacklist
- /etc/ufw # правила, before/after.rules (NAT, форвардинг), /etc/ufw/sysctl.conf
- /etc/default/ufw
- /var/spool/cron/crontabs # crontab root (sudo crontab -e) и пользователей
- /usr/local/sbin/ban.sh
- /etc/sysctl.conf # BBR, форвардинг и прочие правки ядра
- /etc/sysctl.d
- /etc/hosts
# свои задания в /etc/cron.d (пакетные пропускаются)
unowned: ["/etc/cron.d/*"]
post_restore:
- "ufw reload || true"
- "sysctl --system >/dev/null || true"
# SSH: ключи входа, ключи хоста (клиенты не увидят «host key changed») и конфиг sshd
# (порт, запрет паролей). После распаковки sshd проверяется и перезапускается.
- name: ssh
type: files
paths:
- /etc/ssh/sshd_config
- /etc/ssh/sshd_config.d
- /etc/ssh/ssh_host_*
- /root/.ssh/authorized_keys
- /home/*/.ssh/authorized_keys
restore_after: [system]
post_restore:
- "sshd -t && systemctl daemon-reload && (systemctl restart ssh.socket 2>/dev/null; systemctl restart ssh) || echo '!!! sshd: конфиг не прошёл проверку, оставлен старый процесс — проверьте sshd -t'"
# сертификаты, выпущенные вне Caddy: certbot и acme.sh (его использует x-ui для SSL панели)
- name: certs
type: files
paths: [/etc/letsencrypt, /root/.acme.sh]
- name: xui
type: xui
detect: [/usr/local/x-ui/x-ui]
@@ -75,13 +97,22 @@ categories:
detect: [/etc/caddy/Caddyfile]
paths: [/etc/caddy, /var/www, /var/lib/caddy/.local/share/caddy]
service: caddy
# Caddy с плагинами (xcaddy, caddy add-package) из apt не вернуть — тогда бэкапим бинарник
keep_binaries: [/usr/bin/caddy]
keep_binaries_if: "caddy list-modules --packages 2>/dev/null | grep -Eq 'Non-standard modules: [1-9]'"
- name: telegraf
type: systemd
detect: [/etc/telegraf]
paths: [/etc/telegraf, /etc/sudoers.d/telegraf]
paths: [/etc/telegraf, /etc/sudoers.d/telegraf, /etc/default/telegraf]
service: telegraf
# настройки демона docker (логи, MTU, IPv6) и логины в приватные registry
- name: docker
type: systemd
paths: [/etc/docker/daemon.json, /root/.docker/config.json]
service: docker
- name: sing-box-warp
type: systemd
detect: [/opt/sing-box-warp]
@@ -101,6 +132,43 @@ categories:
type: files
paths: [/var/scripts, /usr/local/bin/update-geosite.sh]
# Страховка: всё своё в /etc, не описанное выше, — изменённые конфиги любых пакетов
# (dpkg conffiles: nginx, limits.conf, journald и т.п.) и файлы, не принадлежащие
# ни одному пакету (ключи wireguard, свои конфиги). Привязанное к железу и облаку
# (сеть, диски, cloud-init, зеркала apt, загрузчик) исключено — на новом VPS оно своё.
- name: etc
type: files
modified_conffiles: true
unowned: ["/etc/*/*", "/etc/*/*/*"]
exclude:
- /etc/netplan
- /etc/network
- /etc/NetworkManager
- /etc/systemd/network
- /etc/systemd/system # юниты собирает категория units
- /etc/cloud
- /etc/landscape
- /etc/ubuntu-advantage
- /etc/apt
- /etc/udev
- /etc/fstab
- /etc/default/grub
- /etc/default/grub.d
- /etc/initramfs-tools
- /etc/iscsi
- /etc/lvm
- /etc/mdadm
- /etc/multipath
- /etc/dhcp
- /etc/alternatives
- /etc/apparmor.d/cache
- /etc/ssl/certs
- /etc/ssl/private/ssl-cert-snakeoil.key
- /etc/sudoers.d/90-cloud-init-users
- /etc/machine-id
- /etc/hostname
- /etc/resolv.conf
- name: pnvpanel
type: compose
dir: /opt/PnvPanel
@@ -120,3 +188,10 @@ categories:
type: compose
dir: /opt/psiphon
disabled: true
# Свои systemd-юниты, не описанные выше и не из пакетов, — с состоянием enabled/active,
# и drop-in переопределения пакетных юнитов (*.service.d/override.conf).
- name: units
type: units
unowned: ["/etc/systemd/system/*.service", "/etc/systemd/system/*.timer"]
paths: ["/etc/systemd/system/*.service.d", "/etc/systemd/system/*.timer.d"]