Files
llm-server-setup/backup_ubuntu_config.sh
T

211 lines
7.1 KiB
Bash
Executable File

#!/usr/bin/env bash
set -Eeuo pipefail
readonly SCRIPT_NAME="$(basename "$0")"
readonly DEFAULT_OUTPUT_DIR="/var/backups"
include_secrets=false
output_dir="$DEFAULT_OUTPUT_DIR"
show_help() {
cat <<EOF
Uso: sudo $SCRIPT_NAME [opciones]
Crea un respaldo comprimido de la configuración de Ubuntu para replicarla en
otra instalación. No incluye modelos Ollama, entornos virtuales ni bases de datos.
Opciones:
--output-dir DIR Directorio donde guardar el archivo .tar.gz.
--include-secrets Incluye claves SSH, certificados privados y secretos
de OpenClaw. El archivo resultante debe protegerse.
-h, --help Muestra esta ayuda.
EOF
}
while [[ $# -gt 0 ]]; do
case "$1" in
--output-dir)
[[ $# -ge 2 ]] || { echo "Falta DIR para --output-dir" >&2; exit 2; }
output_dir="$2"
shift 2
;;
--include-secrets)
include_secrets=true
shift
;;
-h|--help)
show_help
exit 0
;;
*)
echo "Opción desconocida: $1" >&2
show_help >&2
exit 2
;;
esac
done
if [[ "${EUID}" -ne 0 ]]; then
echo "Ejecuta este script con sudo o como root." >&2
exit 1
fi
command -v tar >/dev/null || { echo "tar es obligatorio." >&2; exit 1; }
command -v gzip >/dev/null || { echo "gzip es obligatorio." >&2; exit 1; }
hostname_value="$(hostname -s 2>/dev/null || echo unknown)"
timestamp="$(date +%Y%m%d-%H%M%S)"
backup_name="ubuntu-config-${hostname_value}-${timestamp}"
work_dir="$(mktemp -d)"
archive_path="${output_dir}/${backup_name}.tar.gz"
cleanup() {
rm -rf "$work_dir"
}
trap cleanup EXIT
mkdir -p "$work_dir/metadata" "$work_dir/files" "$work_dir/packages" "$work_dir/services"
mkdir -p "$output_dir"
umask 077
copy_path() {
local source="$1"
local destination="$work_dir/files$source"
if [[ -e "$source" || -L "$source" ]]; then
mkdir -p "$(dirname "$destination")"
cp -a "$source" "$destination"
fi
}
capture() {
local name="$1"
shift
"$@" > "$work_dir/metadata/$name.txt" 2>&1 || true
}
capture_shell() {
local name="$1"
local command_text="$2"
bash -c "$command_text" > "$work_dir/metadata/$name.txt" 2>&1 || true
}
printf 'Creando respaldo en %s\n' "$archive_path"
printf '%s\n' "hostname=$hostname_value" "created_at=$(date --iso-8601=seconds)" \
"include_secrets=$include_secrets" > "$work_dir/metadata/backup-info.txt"
capture_shell os-release 'cat /etc/os-release'
capture_shell kernel 'uname -a'
capture_shell hardware 'lscpu; echo; free -h; echo; lsblk -f'
capture_shell disks 'df -hT; echo; findmnt'
capture_shell network 'ip -brief address; echo; ip route; echo; resolvectl status 2>/dev/null || true'
capture_shell users 'getent passwd | awk -F: '\''$3 >= 1000 || $1 == "root" {print $1 ":" $3 ":" $4 ":" $6}'\'''
capture_shell mounts 'mount'
# Registrar nombres, no valores que puedan contener credenciales.
capture_shell environment 'printenv | cut -d= -f1 | sort -u'
capture_shell nvidia 'command -v nvidia-smi && nvidia-smi -q || true'
capture_shell ollama 'command -v ollama && ollama list || true'
capture_shell versions 'command -v node && node --version || true; command -v npm && npm --version || true; command -v python3 && python3 --version || true; command -v ollama && ollama --version || true; command -v openclaw && openclaw --version || true'
capture_shell ufw 'command -v ufw && ufw status verbose || true'
capture_shell iptables 'command -v iptables-save && iptables-save || true'
capture_shell sysctl 'sysctl -a 2>/dev/null'
capture_shell timers 'systemctl list-timers --all --no-pager'
capture_shell enabled-services 'systemctl list-unit-files --state=enabled --no-legend --no-pager'
capture_shell failed-services 'systemctl --failed --no-pager'
if command -v dpkg-query >/dev/null; then
dpkg-query -W -f='${binary:Package}\t${Version}\n' > "$work_dir/packages/dpkg-status.tsv" || true
fi
if command -v apt-mark >/dev/null; then
apt-mark showmanual | sort > "$work_dir/packages/apt-manual.txt" || true
fi
if command -v snap >/dev/null; then
snap list > "$work_dir/packages/snap-list.txt" 2>&1 || true
fi
if command -v pip3 >/dev/null; then
pip3 freeze > "$work_dir/packages/pip3-freeze.txt" 2>&1 || true
fi
systemctl list-unit-files --type=service --no-legend --no-pager \
> "$work_dir/services/all-service-units.txt" 2>&1 || true
systemctl list-unit-files --state=enabled --type=service --no-legend --no-pager \
| awk '{print $1}' | sort -u > "$work_dir/services/enabled-service-names.txt" || true
# Configuración del sistema y de los servicios usados por este proyecto.
for path in \
/etc/apt \
/etc/default \
/etc/environment \
/etc/fstab \
/etc/hostname \
/etc/hosts \
/etc/issue \
/etc/netplan \
/etc/NetworkManager \
/etc/systemd/system \
/etc/sysctl.d \
/etc/modprobe.d \
/etc/ufw \
/etc/ollama \
/etc/nvidia \
/etc/profile.d
do
copy_path "$path"
done
# Configuraciones de usuario que no suelen contener credenciales.
while IFS=: read -r username _ uid _ _ home _; do
[[ -d "$home" ]] || continue
[[ "$uid" -ge 1000 || "$username" == root ]] || continue
for relative_path in .bashrc .profile .config/systemd/user litellm_config.yaml; do
copy_path "$home/$relative_path"
done
printf '%s\t%s\t%s\t%s\n' "$username" "$uid" "$(id -g "$username" 2>/dev/null || echo 0)" "$home" \
>> "$work_dir/metadata/users.tsv"
done < <(getent passwd)
if [[ "$include_secrets" == true ]]; then
printf 'Incluyendo archivos sensibles: SSH, certificados y configuración privada de OpenClaw.\n'
for path in /etc/ssh /etc/ssl/private /etc/letsencrypt; do
copy_path "$path"
done
while IFS=: read -r username _ uid _ _ home _; do
[[ -d "$home" ]] || continue
[[ "$uid" -ge 1000 || "$username" == root ]] || continue
for relative_path in .ssh .openclaw .npmrc; do
copy_path "$home/$relative_path"
done
done < <(getent passwd)
else
cat > "$work_dir/metadata/excluded-secrets.txt" <<EOF
No se incluyeron secretos. Para incluirlos explícitamente, usa:
sudo $SCRIPT_NAME --include-secrets
Excluidos por defecto: /etc/ssh, /etc/ssl/private, /etc/letsencrypt, ~/.ssh,
~/.openclaw y ~/.npmrc.
EOF
fi
cat > "$work_dir/RESTORE.txt" <<EOF
Este archivo fue generado por $SCRIPT_NAME.
1. Instala Ubuntu con la misma arquitectura y crea el usuario de servicio.
2. Copia este archivo a la nueva máquina.
3. Ejecuta restore_ubuntu_config.sh con este archivo y revisa los cambios.
4. Reinstala los modelos Ollama y valida los servicios antes de exponerlos.
El respaldo no contiene modelos Ollama, /opt/litellm-env, bases de datos ni
logs completos. Si no usaste --include-secrets, debes restaurar las credenciales
manualmente.
EOF
printf 'Archivos incluidos:\n'
find "$work_dir" -type f -printf '%P\n' | sort > "$work_dir/metadata/file-list.txt"
cat "$work_dir/metadata/file-list.txt"
tar -C "$work_dir" -czf "$archive_path" .
chmod 600 "$archive_path"
printf '\nRespaldo creado: %s\n' "$archive_path"
printf 'Protección: permisos 600\n'