--- title: Standardizing unattended-upgrades Across Ubuntu Fleet with Ansible domain: selfhosting category: security tags: - ansible - ubuntu - apt - unattended-upgrades - fleet-management status: published created: '2026-03-16' updated: '2026-03-16' --- # Standardizing unattended-upgrades Across Ubuntu Fleet with Ansible When some Ubuntu hosts in a fleet self-update via `unattended-upgrades` and others don't, they drift apart over time — different kernel versions, different reboot states, inconsistent behavior. This article covers how to diagnose the drift and enforce uniform auto-update config across all Ubuntu hosts using Ansible. ## Diagnosing the Problem If only some Ubuntu hosts are flagging for reboot, check: ```bash # What triggered the reboot flag? cat /var/run/reboot-required.pkgs # Is unattended-upgrades installed and active? systemctl status unattended-upgrades cat /etc/apt/apt.conf.d/20auto-upgrades # When did apt last run? ls -lt /var/log/apt/history.log* ``` The reboot flag is written to `/var/run/reboot-required` by `update-notifier-common` when packages like the kernel, glibc, or systemd are updated. If some hosts have `unattended-upgrades` running and others don't, the ones that self-updated will flag for reboot while the others lag behind. ## The Fix — Ansible Playbook Add these tasks to your update playbook **before** the apt cache update step: ```yaml - name: Ensure unattended-upgrades is installed on Ubuntu servers ansible.builtin.apt: name: - unattended-upgrades - update-notifier-common state: present update_cache: true when: ansible_facts['os_family'] == "Debian" - name: Enforce uniform auto-update config on Ubuntu servers ansible.builtin.copy: dest: /etc/apt/apt.conf.d/20auto-upgrades content: | APT::Periodic::Update-Package-Lists "1"; APT::Periodic::Unattended-Upgrade "1"; owner: root group: root mode: '0644' when: ansible_facts['os_family'] == "Debian" - name: Ensure unattended-upgrades service is enabled and running ansible.builtin.systemd: name: unattended-upgrades enabled: true state: started when: ansible_facts['os_family'] == "Debian" ``` Running this across the `ubuntu` group ensures every host has the same config on every Ansible run — idempotent and safe. ## Rebooting Flagged Hosts Once identified, reboot specific hosts without touching the rest: ```bash # Reboot just the flagging hosts ansible-playbook reboot.yml -l teelia,tttpod # Run full update on remaining hosts to bring them up to the same kernel ansible-playbook update.yml -l dca,majorlinux,majortoot ``` ## Notes - `unattended-upgrades` runs daily on its own schedule — hosts that haven't checked yet will lag behind but catch up within 24 hours - The other hosts showing `ok` (not `changed`) on the config tasks means they were already correctly configured - After a kernel update is pulled, only an actual reboot clears the `/var/run/reboot-required` flag — Ansible reporting the flag is informational only ## See Also - [Ansible Getting Started](../../01-linux/shell-scripting/ansible-getting-started.md) - [Linux Server Hardening Checklist](linux-server-hardening-checklist.md)