From 4903bd44957b3c25e7fddc9d0c54c08efb1c6e9f Mon Sep 17 00:00:00 2001 From: mike Date: Thu, 24 Jul 2025 20:33:01 +0000 Subject: [PATCH] Add auto-updates-full.sh --- auto-updates-full.sh | 180 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 auto-updates-full.sh diff --git a/auto-updates-full.sh b/auto-updates-full.sh new file mode 100644 index 0000000..9a0d9fe --- /dev/null +++ b/auto-updates-full.sh @@ -0,0 +1,180 @@ +#!/usr/bin/env bash +# +# setup-auto-updates.sh +# +# Debian/Ubuntu universal unattended-upgrades setup: +# - fixes locale (en_US.UTF-8) to avoid perl/locale warnings +# - installs & enables unattended-upgrades +# - security + regular updates (kernels included) +# - smart reboot at 04:00 (only when needed, and no logged-in users) +# - no email configuration +# - optional self-deletion at end + +set -Eeuo pipefail +trap 'echo "[ERROR] Line $LINENO failed" >&2' ERR + +REBOOT_TIME="04:00" +TARGET_LOCALE="en_US.UTF-8" + +require_root() { + if [[ $EUID -ne 0 ]]; then + echo "[ERROR] Run as root (sudo)" >&2 + exit 1 + fi +} + +detect_os() { + if [[ ! -f /etc/os-release ]]; then + echo "[ERROR] /etc/os-release not found" >&2 + exit 1 + fi + . /etc/os-release + case "$ID" in + ubuntu) OS="ubuntu" ;; + debian) OS="debian" ;; + *) echo "[ERROR] Unsupported OS: $ID" >&2; exit 1 ;; + esac + CODENAME="${VERSION_CODENAME:-$UBUNTU_CODENAME}" + echo "[INFO] Detected: $PRETTY_NAME ($OS / $CODENAME)" +} + +fix_locale() { + echo "[INFO] Ensuring locale ${TARGET_LOCALE} is generated…" + apt-get update -y >/dev/null 2>&1 || true + DEBIAN_FRONTEND=noninteractive apt-get install -y locales >/dev/null 2>&1 || true + + if [[ -f /etc/locale.gen ]]; then + if grep -qE "^\s*#\s*${TARGET_LOCALE}\s+UTF-8" /etc/locale.gen; then + sed -ri "s/^\s*#\s*(${TARGET_LOCALE}\s+UTF-8)/\1/" /etc/locale.gen + elif ! grep -qE "^\s*${TARGET_LOCALE}\s+UTF-8" /etc/locale.gen; then + echo "${TARGET_LOCALE} UTF-8" >> /etc/locale.gen + fi + else + echo "${TARGET_LOCALE} UTF-8" > /etc/locale.gen + fi + + locale-gen + update-locale LANG=${TARGET_LOCALE} LC_ALL=${TARGET_LOCALE} + export LANG=${TARGET_LOCALE} + export LC_ALL=${TARGET_LOCALE} +} + +install_unattended() { + echo "[INFO] Updating apt cache…" + apt update + echo "[INFO] Installing unattended-upgrades…" + DEBIAN_FRONTEND=noninteractive apt install -y unattended-upgrades +} + +enable_unattended() { + echo "[INFO] Enabling unattended-upgrades via debconf…" + echo 'unattended-upgrades unattended-upgrades/enable_auto_updates boolean true' | debconf-set-selections + DEBIAN_FRONTEND=noninteractive dpkg-reconfigure -f noninteractive unattended-upgrades +} + +write_50_conf_ubuntu() { + cat > /etc/apt/apt.conf.d/50unattended-upgrades < /etc/apt/apt.conf.d/50unattended-upgrades < /etc/apt/apt.conf.d/20auto-upgrades <<'EOF' +APT::Periodic::Update-Package-Lists "1"; +APT::Periodic::Download-Upgradeable-Packages "1"; +APT::Periodic::AutocleanInterval "7"; +APT::Periodic::Unattended-Upgrade "1"; +EOF +} + +dry_run_test() { + echo "[INFO] Dry-run unattended-upgrades (debug)…" + unattended-upgrades --dry-run --debug > /tmp/unattended-upgrades-test.log 2>&1 || true + echo "[INFO] Tail of /tmp/unattended-upgrades-test.log:" + tail -n 30 /tmp/unattended-upgrades-test.log || true +} + +show_status() { + echo "[INFO] apt timers:" + systemctl list-timers --all | grep -E 'apt-(daily|daily-upgrade)\.timer' || true + echo + echo "[INFO] Config files written:" + ls -l /etc/apt/apt.conf.d/20auto-upgrades /etc/apt/apt.conf.d/50unattended-upgrades +} + +prompt_self_delete() { + echo + read -r -p "Remove this script? [Y/n] " confirm + case "$confirm" in + [nN]*) echo "[INFO] Script not removed." ;; + *) echo "[INFO] Removing script: $0"; rm -- "$0" ;; + esac +} + +main() { + require_root + detect_os + fix_locale + install_unattended + enable_unattended + + echo "[INFO] Writing /etc/apt/apt.conf.d/50unattended-upgrades…" + if [[ "$OS" == "ubuntu" ]]; then + write_50_conf_ubuntu + else + write_50_conf_debian + fi + + echo "[INFO] Writing /etc/apt/apt.conf.d/20auto-upgrades…" + write_20_conf + + dry_run_test + show_status + + echo "[OK] Unattended updates configured. Security + regular updates, reboot @ ${REBOOT_TIME} if needed." + prompt_self_delete +} + +main "$@"