You've already forked auto-update-ubuntu
latest commit
This commit is contained in:
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -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.
|
||||
233
README.md
Normal file
233
README.md
Normal file
@@ -0,0 +1,233 @@
|
||||
# Unattended Upgrades Policy for Ubuntu 24.04 Server
|
||||
|
||||

|
||||
[](#)
|
||||

|
||||
|
||||
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 <mode>
|
||||
```
|
||||
|
||||
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).
|
||||
|
||||
---
|
||||
259
auto-upgrade-new
Executable file
259
auto-upgrade-new
Executable file
@@ -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 <<EOF
|
||||
Usage: $0 <mode>
|
||||
|
||||
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" <<EOF
|
||||
#
|
||||
# Managed by: auto-update-ubuntu
|
||||
# Purpose : OPS-controlled unattended upgrades
|
||||
# Schedule : Every Friday at 03:00
|
||||
#
|
||||
0 3 * * 5 root /usr/bin/apt update && /usr/bin/unattended-upgrade -v >/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
|
||||
4
last-tested
Normal file
4
last-tested
Normal file
@@ -0,0 +1,4 @@
|
||||
------------------------------------
|
||||
Last tested: 28-01-2026 (DD-MM-YYYY)
|
||||
Environment: Ubuntu Server 24.04 LTS
|
||||
------------------------------------
|
||||
Reference in New Issue
Block a user