From 552f8c566dff9b2efa6ad60b33f546a2e5773e83 Mon Sep 17 00:00:00 2001 From: allan Date: Fri, 30 Jan 2026 09:35:27 +0100 Subject: [PATCH] latest commit --- LICENSE | 21 ++++ README.md | 233 ++++++++++++++++++++++++++++++++++++++++++ auto-upgrade-new | 259 +++++++++++++++++++++++++++++++++++++++++++++++ last-tested | 4 + 4 files changed, 517 insertions(+) create mode 100644 LICENSE create mode 100644 README.md create mode 100755 auto-upgrade-new create mode 100644 last-tested diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3eaaa81 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Allan Christensen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..5aa8161 --- /dev/null +++ b/README.md @@ -0,0 +1,233 @@ +# Unattended Upgrades Policy for Ubuntu 24.04 Server + +![Ubuntu](https://img.shields.io/badge/Ubuntu-24.04-orange) +[![Feature](https://img.shields.io/badge/feature-controlled_updates-0078D7)](#) +![License](https://img.shields.io/badge/License-MIT-green) + +Install unattended upgrades on Ubuntu 24.04 server — with **explicit OPS control**. + +> **Production notice** +> This script configures automatic updates and optional automatic reboots. +> Read and understand the policy modes before applying it on production systems. + +--- + +## Why this installer exists + +Ubuntu already ships with unattended upgrades — but the defaults are a bear trap. + +This installer exists to give **OPS full control** over: + +- what gets updated +- when updates run +- whether systems reboot automatically +- how users are impacted + +No hidden timers. +No silent defaults. +No surprises. + +--- + +## What this installer does + +✔ Installs required packages (`unattended-upgrades`, `update-notifier-common`) +✔ Disables Ubuntu’s automatic APT timers +✔ Enforces **one explicit update policy (mode 1–4)** +✔ Configures unattended-upgrades accordingly +✔ Creates a controlled cron job +✔ Backs up original configuration files **once**, in-place +✔ Can be safely re-run to switch policies +✔ Does **NOT** enable automatic package removal (`apt autoremove`) + +--- + +## What this installer does NOT do + +It won’t stop you from running the script without reading the documentation like there’s no tomorrow. +Skip the README, and whatever happens next is your headache, not a bug report. + +--- + +## Supported systems + +- Ubuntu **24.04 Server** +- Designed for **servers**, not desktops +- Not intended for containers or Docker images + +--- + +## Before you run the script + +Update package metadata **manually**: + +``` +apt update +``` + +This is intentionally not done by the script. + +--- + +## Installation + +Clone the repository: + +``` +git clone https://git.x-files.dk/server/auto-update-ubuntu.git +``` + +Change into the directory: + +``` +cd auto-update-ubuntu +``` + +--- + +## Usage + +The script is **non-interactive** and **argument-driven**. + +You must select **exactly one mode**: + +``` +sudo ./auto-update-ubuntu +``` + +Example: + +``` +sudo ./auto-update-ubuntu 1 +``` + +### Available modes + +**Mode 1** +- Security **and** software updates +- Automatic reboot +- Reboot happens even if users are logged in + +**Mode 2** +- Security **and** software updates +- No automatic reboot +- Users are notified on next login if a reboot is required + +**Mode 3** +- Security updates only +- Automatic reboot +- Reboot happens even if users are logged in + +**Mode 4** +- Security updates only +- No automatic reboot +- Users are notified on next login if a reboot is required + +Running the script again with a different mode will **overwrite the previous policy**. + +--- + +## Cron schedule + +Updates are executed via cron: + +- **Every Friday at 03:00** +- Command executed: + ``` + apt update && unattended-upgrade -v + ``` + +The cron file is managed at: + +``` +/etc/cron.d/updatesystem +``` + +Re-running the script will always reassert this schedule. + +--- + +## Backups and rollback + +### Full rollback (restore Ubuntu defaults) + +This rollback **fully returns the system to Ubuntu’s default unattended-upgrades behavior**. + +It restores the original configuration files, removes the OPS-controlled cron job, and hands scheduling control back to Ubuntu’s built-in APT timers. +Partial rollback is **not recommended**. + +--- + +### 1. Restore original configuration files + +``` +sudo cp /etc/apt/apt.conf.d/20auto-upgrades.orig /etc/apt/apt.conf.d/20auto-upgrades +sudo cp /etc/apt/apt.conf.d/50unattended-upgrades.orig /etc/apt/apt.conf.d/50unattended-upgrades +``` + +Restart unattended-upgrades: + +``` +sudo systemctl restart unattended-upgrades.service +``` + +--- + +### 2. Re-enable Ubuntu’s default APT timers (important) + +This script disables and masks Ubuntu’s automatic APT timers to ensure OPS-controlled scheduling. + +To restore Ubuntu defaults: + +``` +sudo systemctl unmask apt-daily.service apt-daily-upgrade.service +sudo systemctl enable --now apt-daily.timer apt-daily-upgrade.timer +``` + +--- + +### 3. Remove the OPS-controlled cron job + +``` +sudo rm -f /etc/cron.d/updatesystem +sudo systemctl restart cron.service +``` + +--- + +### Important note about collisions + +Do **not** run Ubuntu’s APT timers **and** this cron job at the same time. + +Doing so may result in: +- concurrent APT locks +- unpredictable update timing +- reboots outside approved maintenance windows + +Choose **one scheduling mechanism only**. + +--- + +## Operational notes + +- The script is silent on success +- Invalid or missing arguments cause a hard failure +- No defaults are assumed +- All configuration is **authoritative**, not incremental + +This is a **policy tool**, not a wizard. + +--- + +### More Information + +More guides and documentation can be found on [wiki.x-files.dk](https://wiki.x-files.dk) + +--- + +### License + +Licensed under the MIT License. +Licensed under the [MIT License](./LICENSE). + +--- diff --git a/auto-upgrade-new b/auto-upgrade-new new file mode 100755 index 0000000..b96a45c --- /dev/null +++ b/auto-upgrade-new @@ -0,0 +1,259 @@ +#!/usr/bin/env bash + +# Author : Allan Christensen +# First Created : 23-06-2022 (DD-MM-YYYY) +# Description : OPS-controlled unattended-upgrades policy configuration for Ubuntu 24.04 +# License : MIT License + +# +# Are we root +# +if [[ $(id -u) -ne 0 ]]; then + echo "" + echo "Must be root or use sudo" + echo "" + exit 1 +fi + +# +# Variables +# +mode="${1:-}" + +config1="/etc/apt/apt.conf.d/20auto-upgrades" +config1alt="/usr/share/unattended-upgrades/20auto-upgrades" + +config2="/etc/apt/apt.conf.d/50unattended-upgrades" +config2alt="/usr/share/unattended-upgrades/50unattended-upgrades" + +cronfile="/etc/cron.d/updatesystem" + +# +# Functions +# +die () { + echo "Error: $*" >&2 + exit 1 +} + +usage () { + cat < + +Please select ONE of the following modes: + + 1 Security + software updates + Automatic reboot immediately after upgrades complete + + 2 Security + software updates + No automatic reboot + Users will be notified on next login if a reboot is required + + 3 Security updates only + Automatic reboot immediately after upgrades complete + + 4 Security updates only + No automatic reboot + Users will be notified on next login if a reboot is required +EOF + exit 1 +} + +chkcfg () { + if [[ ! -f "$1" ]]; then + [[ -f "$2" ]] || die "Missing source config: $2" + cp -Rp "$2" "$1" || die "Failed to copy $2 to $1" + fi +} + +mkorig () { + if [[ ! -f "${1}.orig" ]]; then + cp -Rp "$1" "${1}.orig" || die "Failed to create backup: ${1}.orig" + fi +} + +# +# Disable Ubuntu automatic timers (OPS owns scheduling) +# +disable_apt_timers () { + systemctl disable --now apt-daily.timer apt-daily-upgrade.timer >/dev/null 2>&1 || true + systemctl mask apt-daily.service apt-daily-upgrade.service >/dev/null 2>&1 || true +} + +# +# Ensure periodic jobs are disabled (cron owns execution) +# +set_20auto () { + sed -i 's|^\s*APT::Periodic::Update-Package-Lists.*|APT::Periodic::Update-Package-Lists "0";|' "$config1" + sed -i 's|^\s*APT::Periodic::Unattended-Upgrade.*|APT::Periodic::Unattended-Upgrade "0";|' "$config1" +} + +# +# Allowed origins – explicit, Bash-native +# +set_allowed_origins () { + local allow_updates="$1" + + # + # Always enable security updates + # + sed -i \ + '/^\s*\/\/\s*"\${distro_id}:\${distro_codename}-security"/ s|^\s*//\s*||' \ + "$config2" + + # + # Enable or disable non-security updates + # + if [[ "$allow_updates" == "true" ]]; then + sed -i \ + '/^\s*\/\/\s*"\${distro_id}:\${distro_codename}-updates"/ s|^\s*//\s*||' \ + "$config2" + else + sed -i \ + '/^\s*"\${distro_id}:\${distro_codename}-updates"/ s|^|// |' \ + "$config2" + fi +} + +# +# Reboot policy – immediate reboot after upgrades +# +set_reboot_policy () { + local reboot="$1" + local reboot_with_users="$2" + + # + # Automatic-Reboot (exact key only) + # + sed -i \ + '/^\s*\/\/\s*Unattended-Upgrade::Automatic-Reboot\s/ s|^\s*//\s*||' \ + "$config2" + sed -i \ + 's|^\s*Unattended-Upgrade::Automatic-Reboot\s*".*";|Unattended-Upgrade::Automatic-Reboot "'"$reboot"'";|' \ + "$config2" + + # + # Automatic-Reboot-WithUsers (exact key only) + # + sed -i \ + '/^\s*\/\/\s*Unattended-Upgrade::Automatic-Reboot-WithUsers\s/ s|^\s*//\s*||' \ + "$config2" + sed -i \ + 's|^\s*Unattended-Upgrade::Automatic-Reboot-WithUsers\s*".*";|Unattended-Upgrade::Automatic-Reboot-WithUsers "'"$reboot_with_users"'";|' \ + "$config2" + + # + # Ensure reboot-time stays commented (cron defines timing) + # + sed -i \ + '/^\s*Unattended-Upgrade::Automatic-Reboot-Time/ s|^|// |' \ + "$config2" +} + +# +# Cron – authoritative schedule +# +write_cron () { + cat > "$cronfile" </dev/null 2>&1 +EOF + + chmod 644 "$cronfile" || die "Failed chmod on $cronfile" + chown root:root "$cronfile" || die "Failed chown on $cronfile" +} + +restart_services () { + systemctl restart unattended-upgrades.service >/dev/null 2>&1 || die "Failed to restart unattended-upgrades" + systemctl restart cron.service >/dev/null 2>&1 || die "Failed to restart cron" +} + +# +# Validate mode +# +case "$mode" in + 1|2|3|4) ;; + *) usage ;; +esac + +# +# Informational output (configuration-time only) +# +echo "Applying unattended-upgrades policy:" +echo "" + +case "$mode" in + 1) + echo " Mode: 1" + echo " Updates: Security + software updates" + echo " Reboot: Immediate reboot after upgrades complete" + ;; + 2) + echo " Mode: 2" + echo " Updates: Security + software updates" + echo " Reboot: Disabled" + echo " User notification: On next login if a reboot is required" + ;; + 3) + echo " Mode: 3" + echo " Updates: Security updates only" + echo " Reboot: Immediate reboot after upgrades complete" + ;; + 4) + echo " Mode: 4" + echo " Updates: Security updates only" + echo " Reboot: Disabled" + echo " User notification: On next login if a reboot is required" + ;; +esac + +echo "" + +# +# Packages (no implicit apt update) +# +apt-get -y -qq install unattended-upgrades update-notifier-common >/dev/null \ + || die "Package install failed" + +# +# Ensure configs exist +# +chkcfg "$config1" "$config1alt" +chkcfg "$config2" "$config2alt" + +# +# Backup originals (once) +# +mkorig "$config1" +mkorig "$config2" + +# +# OPS-owned execution model +# +set_20auto +disable_apt_timers + +# +# Apply policy +# +case "$mode" in + 1|2) set_allowed_origins "true" ;; + 3|4) set_allowed_origins "false" ;; +esac + +case "$mode" in + 1|3) set_reboot_policy "true" "true" ;; + 2|4) set_reboot_policy "false" "false" ;; +esac + +# +# Cron + services +# +write_cron +restart_services + +exit 0 diff --git a/last-tested b/last-tested new file mode 100644 index 0000000..46c28b6 --- /dev/null +++ b/last-tested @@ -0,0 +1,4 @@ +------------------------------------ +Last tested: 28-01-2026 (DD-MM-YYYY) +Environment: Ubuntu Server 24.04 LTS +------------------------------------