How to Configure Unattended Upgrades on Ubuntu Linux

Keeping Ubuntu servers patched against security vulnerabilities requires constant vigilance, or dependable automation. The unattended-upgrades package handles security updates silently in the background, downloading and installing critical fixes from Canonical without manual intervention. Whether you manage production servers that need patches applied overnight, development VMs requiring the latest security updates without disrupting your workflow, or home systems that should stay protected while you focus on other tasks, automating this process reduces risk while freeing you from repetitive maintenance.

This guide walks you through installing, configuring, and fine-tuning unattended-upgrades on Ubuntu LTS releases. You will learn how to control which updates install automatically, schedule maintenance windows that avoid disrupting services, configure email notifications for awareness, and balance security needs against stability requirements using real-world configuration patterns tested on production systems.

How Unattended Upgrades Works

Once enabled, the system follows this workflow:

  1. Schedule check: The apt-daily-upgrade.timer systemd unit triggers the upgrade process (default: twice daily with randomized delays)
  2. Repository refresh: Updates package lists from configured repositories
  3. Filter packages: Applies your allowed origins, blacklists, and other rules to determine which updates qualify
  4. Download: Fetches packages in the background without disrupting system performance
  5. Install: Applies updates in minimal steps, allowing interruption if needed
  6. Cleanup: Removes old packages, unused dependencies, and outdated kernels based on your configuration
  7. Reboot (if configured): Automatically restarts the system during your specified maintenance window when kernel or critical library updates require it

Key Files and Components

File/ComponentPurpose
/etc/apt/apt.conf.d/50unattended-upgradesMain configuration file controlling which packages to install, blacklists, email settings, and automatic reboot behavior
/etc/apt/apt.conf.d/20auto-upgradesEnables or disables automatic updates and controls update frequency
/var/log/unattended-upgrades/Dedicated log directory containing detailed upgrade history and dpkg output
apt-daily.timerSystemd timer that triggers package list updates
apt-daily-upgrade.timerSystemd timer that triggers actual package installations
unattended-upgrades.serviceMain systemd service that performs the upgrade operations

Benefits and Features of Unattended Upgrades

Here are the key benefits and features of automating updates with unattended-upgrades on Ubuntu:

  • Automated updates: The package automates downloading and installing updates, saving time and reducing the window of exposure to known vulnerabilities.
  • Improved security: By ensuring the system receives the latest security updates and patches automatically, it reduces the risk of malware attacks and system vulnerabilities.
  • Enhanced stability: Regular updates ensure the system benefits from bug fixes and improvements that enhance overall reliability.
  • Customizable settings: You can customize package settings to control which updates install automatically, which to ignore, and when to install them.
  • Notification system: When configured, the package sends email notifications about installed updates, providing transparency and control over system changes.

Update Ubuntu Before Installation

Before installing unattended-upgrades, refresh your package lists and apply any pending updates to avoid conflicts during installation. Run the following command:

sudo apt update && sudo apt upgrade

This command refreshes repository metadata and upgrades installed packages to their latest versions. Depending on how many updates are queued, this may take a few minutes to complete.

Install Unattended-Upgrades Package

Most Ubuntu installations include unattended-upgrades by default, but minimal server images or containers may lack it. First, verify whether it’s already installed:

dpkg -l | grep unattended-upgrades

If the package is missing, install it with:

sudo apt install unattended-upgrades

For laptop users who want to prevent updates from draining battery power, additionally install the power management package that enables battery-aware upgrade behavior:

sudo apt install powermgmt-base

This package allows unattended-upgrades to skip updates when running on battery power, avoiding unexpected power drain during mobile use. Configure this behavior later in the OnlyOnACPower setting.

Enable Periodic Updates

Installing the package is only part of the job. Ubuntu uses /etc/apt/apt.conf.d/20auto-upgrades to decide whether unattended upgrades should run at all, and minimal/cloud images often ship with automation disabled. Check the current values:

cat /etc/apt/apt.conf.d/20auto-upgrades

You should see at least the following entries set to "1" so package lists refresh daily and the unattended-upgrades hook runs automatically:

APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";

If the file is missing or set to "0", either edit it manually with sudo nano /etc/apt/apt.conf.d/20auto-upgrades or rerun the debconf helper, which prompts you to enable unattended upgrades and writes the correct values:

sudo dpkg-reconfigure --priority=low unattended-upgrades

Once these settings are in place, the systemd timers created by the package will follow the configured cadence without further manual intervention.

Verify Installation and Service Status

After installation, confirm unattended-upgrades is active and ready to run. Check the service status with:

systemctl status unattended-upgrades

You should see “active (running)” in the output. Additionally, test your configuration without making actual changes using the dry-run mode:

sudo unattended-upgrades --dry-run --debug

This command simulates the upgrade process, showing which packages would be upgraded and revealing any configuration errors before they affect your system. Look for messages indicating packages were identified and would be installed if running normally.

Service Management Commands

Use these systemctl commands to manage the unattended-upgrades service when you need to pause updates temporarily, restart after configuration changes, or control boot behavior:

CommandPurpose
sudo systemctl start unattended-upgradesStart the service immediately
sudo systemctl stop unattended-upgradesStop the service (useful during maintenance)
sudo systemctl restart unattended-upgradesRestart to apply configuration changes
sudo systemctl enable unattended-upgradesEnable automatic start at boot
sudo systemctl disable unattended-upgradesPrevent automatic start at boot

Command-Line Options Reference

When running unattended-upgrades manually or testing configurations, these options control its behavior:

OptionDescription
-h, --helpDisplays the help message and exits
-d, --debugEnables debug messages showing detailed processing steps
--apt-debugMakes apt/libapt print verbose debug messages
-v, --verboseEnables info messages for additional context
--dry-runSimulates upgrade process without installing anything (essential for testing)
--download-onlyDownloads upgrades but does not install them
--minimal-upgrade-stepsUpgrades packages in minimal steps (default behavior, allows SIGTERM interruption)
--no-minimal-upgrade-stepsUpgrades all packages together instead of in smaller sets

The --dry-run option is particularly valuable when testing configuration changes on production systems. Use it liberally to preview what would happen before committing to automatic installations.

Configure Unattended Upgrades

Once installation is complete and the service is verified, the next step is configuring unattended-upgrades through its main configuration file. Each setting is optional and adapts to your specific requirements. Production servers typically need conservative settings with controlled reboot windows, while development systems can be more aggressive with updates. Before making changes, back up the original configuration:

sudo cp /etc/apt/apt.conf.d/50unattended-upgrades /etc/apt/apt.conf.d/50unattended-upgrades.backup

This backup allows quick restoration if a configuration change causes issues.

Editing the Configuration File

Open the main configuration file with your preferred text editor. Using nano with root privileges:

sudo nano /etc/apt/apt.conf.d/50unattended-upgrades

The configuration file contains commented lines (beginning with // or #). Remove the comment markers from lines you want to activate, modify the values as needed, then save and exit by pressing Ctrl+X, followed by Y, then Enter.

Allowed Origins

This setting controls which Ubuntu repositories can provide automatic updates. Ubuntu enables the base release and security pockets by default, while the rest stay commented until you manually allow them. The standard configuration looks like this:

Unattended-Upgrade::Allowed-Origins {
      "${distro_id}:${distro_codename}";
      "${distro_id}:${distro_codename}-security";
//    "${distro_id}:${distro_codename}-updates";
//    "${distro_id}:${distro_codename}-proposed";
//    "${distro_id}:${distro_codename}-backports";
};

Leave the base release and -security lines active, then remove the leading // when you genuinely need -updates. Keep -proposed or -backports disabled on production nodes because they deliver pre-release or rapidly changing packages that can break workloads. Development systems can selectively enable additional pockets when testing newer builds.

Package Blacklist

Beyond controlling repository sources, you can exclude specific packages from automatic updates. This is critical when an unattended patch could break a workload. Common examples include database servers, web servers with custom modules, or kernel versions pinned for driver compatibility. To blacklist packages:

Unattended-Upgrade::Package-Blacklist {
      "my-package";
      "my-other-package";
};

Common blacklist candidates include postgresql-* (database clusters needing planned downtime), nginx or apache2 (web servers with custom configuration), linux-image-* (kernel updates requiring specific validation), and any packages where version changes require coordinated service restarts across a cluster.

AutoFixInterruptedDpkg

When dpkg installations get interrupted (power failures, network issues, manual termination), the package system can be left in an inconsistent state. Enable this setting to automatically repair interrupted installations before attempting new updates:

Unattended-Upgrade::AutoFixInterruptedDpkg "true";

This is particularly useful for systems prone to unexpected reboots or network interruptions. It essentially runs dpkg --configure -a before proceeding with updates.

MinimalSteps

This setting controls whether packages upgrade in small batches or all at once. The default minimal-steps approach installs packages incrementally, allowing you to interrupt the process with SIGTERM if needed without leaving the system in a completely broken state:

Unattended-Upgrade::MinimalSteps "true";

Disable this ("false") only when you need faster bulk upgrades and can tolerate potential interruption complications. Most systems should keep this enabled.

InstallOnShutdown

By default, unattended-upgrades installs packages via scheduled systemd timers while the system runs. Alternatively, you can defer installations until system shutdown instead:

Unattended-Upgrade::InstallOnShutdown "true";

This is useful for desktop systems where you want updates staged but not applied until you’re done working. Note that updates won’t happen if the system stays powered on continuously, so servers should leave this disabled.

Mail and MailReport Settings

After configuring which packages update and when installations occur, configure email notifications to stay informed about automatic update activity without manually checking logs. First, specify your email address:

Unattended-Upgrade::Mail "example@mail.com";

Then control when emails send with the MailReport setting:

Unattended-Upgrade::MailReport "on-change";

Valid options are "on-change" (only when packages were upgraded), "only-on-error" (only when problems occur), or "always" (every time unattended-upgrades runs). For production servers, use "on-change" or "only-on-error" to avoid inbox noise while maintaining visibility into security patching activity.

Email notifications require a working mail transfer agent like Postfix or Exim. Test your mail configuration with echo "Test" | mail -s "Test Subject" your@email.com before relying on unattended-upgrades notifications.

Automatic Reboot Configuration

Kernel updates, glibc upgrades, and certain system library patches require reboots to take effect. Configure automatic reboot behavior with these settings:

Unattended-Upgrade::Automatic-Reboot "true";

This enables automatic reboots when required. However, for production servers, always combine this with a specific reboot time to avoid unexpected downtime:

Unattended-Upgrade::Automatic-Reboot-Time "03:00";

Additionally, control whether reboots proceed when users are logged in:

Unattended-Upgrade::Automatic-Reboot-WithUsers "false";

Production Warning: Automatic reboots can disrupt services if not carefully scheduled. For production systems, either disable automatic reboots entirely and handle them manually during maintenance windows, or ensure the reboot time aligns with low-traffic periods and implement proper monitoring to detect unexpected restarts. Consider clustering or load balancing that tolerates individual node reboots before enabling this feature.

Package Cleanup Settings

In addition to managing automatic updates, control automatic removal of unnecessary packages to prevent disk space accumulation over time:

Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";

This removes old kernel versions automatically after successful upgrades. Keep one or two old kernels for emergency boot options, but don’t let them pile up indefinitely.

Unattended-Upgrade::Remove-New-Unused-Dependencies "true";

This removes new dependencies that became unnecessary after package upgrades. It’s similar to running apt autoremove automatically after each upgrade cycle.

Unattended-Upgrade::Remove-Unused-Dependencies "true";

This aggressively removes all unused dependencies, not just newly orphaned ones. Enable this on space-constrained systems, but note it may remove packages you manually installed if they’re not explicitly marked as manually installed in APT’s database.

Additional Configuration Options

Beyond the core settings covered above, these additional options fine-tune behavior for specific scenarios:

Download speed limiting: Throttle package downloads to prevent saturating your network connection (value in KB/s):

Acquire::http::Dl-Limit "100";

Syslog configuration: Enable or disable logging upgrade events to syslog, and choose which facility receives the messages:

Unattended-Upgrade::SyslogEnable "true";
Unattended-Upgrade::SyslogFacility "daemon";

Battery power restrictions: On laptops with powermgmt-base installed, skip updates when running on battery:

Unattended-Upgrade::OnlyOnACPower "true";

Metered connection handling: Prevent downloads over cellular or other metered connections:

Unattended-Upgrade::Skip-Updates-On-Metered-Connections "true";

Debug output: Enable verbose or debug logging when troubleshooting configuration issues:

Unattended-Upgrade::Verbose "true";
Unattended-Upgrade::Debug "true";

Allow downgrades: Permit package downgrades during updates (use with extreme caution):

Unattended-Upgrade::Allow-downgrade "true";

Allowing downgrades can introduce security vulnerabilities and system instability. Only enable this temporarily when troubleshooting specific package version issues, and disable it immediately after resolving the problem.

Testing Configuration Changes

After modifying the configuration file, always test your changes before relying on automatic operations. Run a dry-run to simulate what would happen:

sudo unattended-upgrades --dry-run --debug

Review the output carefully for any errors or warnings. Look for messages indicating which packages qualified for upgrade and whether your blacklist rules work as expected. Once you confirm the dry-run succeeds, apply your configuration by restarting the service:

sudo systemctl restart unattended-upgrades

Real-World Configuration Examples

With configuration options understood, these practical examples demonstrate how to balance security, stability, and operational requirements across different system types. Each example reflects settings tested on production infrastructure.

Example 1: Production Server Configuration (Conservative)

Production servers prioritize stability and controlled maintenance windows. This configuration installs only security updates, blacklists critical services, and schedules reboots during documented maintenance windows:

// Allowed origins - security updates only
Unattended-Upgrade::Allowed-Origins {
    "${distro_id}:${distro_codename}-security";
};

// Blacklist critical services
Unattended-Upgrade::Package-Blacklist {
    "postgresql-*";
    "nginx";
    "redis-*";
};

// Automatic reboot at 3 AM, never with active users
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "03:00";
Unattended-Upgrade::Automatic-Reboot-WithUsers "false";

// Email notifications on changes
Unattended-Upgrade::Mail "ops@example.com";
Unattended-Upgrade::MailReport "on-change";

// Conservative cleanup
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Remove-New-Unused-Dependencies "true";

This setup keeps the server patched against known vulnerabilities while allowing ops teams to manually update application stacks during scheduled change windows.

Example 2: Development Workstation (Aggressive)

In contrast to production servers, development machines benefit from bleeding-edge updates and can tolerate occasional breakage. This configuration pulls from multiple repositories and performs aggressive cleanup:

// Allowed origins - security, updates, and backports
Unattended-Upgrade::Allowed-Origins {
    "${distro_id}:${distro_codename}-security";
    "${distro_id}:${distro_codename}-updates";
    "${distro_id}:${distro_codename}-backports";
};

// No package blacklist - update everything

// Auto-reboot at 2 AM when no one is working
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "02:00";

// Aggressive cleanup to save disk space
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";
Unattended-Upgrade::Remove-New-Unused-Dependencies "true";

// Laptop-specific: skip updates on battery
Unattended-Upgrade::OnlyOnACPower "true";

This keeps development environments current with the latest features while avoiding battery drain during mobile work sessions.

Example 3: Home Media Server (Balanced)

Finally, home servers balance security with minimal user disruption. This configuration applies security patches automatically but blacklists packages that might interrupt media streaming:

// Allowed origins - security and stable updates
Unattended-Upgrade::Allowed-Origins {
    "${distro_id}:${distro_codename}-security";
    "${distro_id}:${distro_codename}-updates";
};

// Blacklist media-related packages for manual updates
Unattended-Upgrade::Package-Blacklist {
    "plex*";
    "jellyfin*";
    "docker*";
};

// Auto-reboot at 4 AM only when no users logged in
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "04:00";
Unattended-Upgrade::Automatic-Reboot-WithUsers "false";

// Standard cleanup
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Remove-New-Unused-Dependencies "true";

This approach keeps the server secure without disrupting movie nights or scheduled recordings.

Understanding Automatic Update Scheduling

Ubuntu manages unattended-upgrades scheduling through systemd timers rather than traditional cron jobs. After installation, the system automatically configures two timers that handle the update cycle without requiring manual cron setup.

Default Systemd Timer Behavior

To understand how your system currently schedules updates, check the timer schedule with:

systemctl list-timers apt-daily.timer apt-daily-upgrade.timer --all

This shows when each timer last ran and when it will trigger next. Including the .timer suffix and the --all flag ensures systemd reports the exact units even if they are disabled. The apt-daily.timer updates package lists, while apt-daily-upgrade.timer performs actual installations. Both timers include randomized delays to prevent thousands of Ubuntu systems from hammering Canonical’s servers simultaneously.

View detailed timer configuration:

systemctl cat apt-daily-upgrade.timer

The default schedule runs twice daily with staggered delays, typically once in early morning and again in early evening. Randomization means your specific system’s schedule varies within these windows.

Manual Cron Job Scheduling (Optional)

Most systems should rely on the default systemd timers. However, if you need precise control over execution timing or want to integrate with existing cron-based workflows, you can create a manual cron job. Note that this approach bypasses systemd’s built-in randomization and logging integration.

To create a custom cron schedule, edit root’s crontab:

sudo crontab -e

Add this line to run unattended-upgrades daily at midnight:

0 0 * * * /usr/bin/unattended-upgrade -d

The -d flag enables detailed logging output. Save and exit (Ctrl+X, Y, Enter). When using manual cron, disable the systemd timers to avoid duplicate upgrade attempts:

sudo systemctl disable apt-daily-upgrade.timer
sudo systemctl stop apt-daily-upgrade.timer

Leave apt-daily.timer enabled in most cases so package lists stay fresh before your cron job runs. Only disable it if your cron workflow already performs apt update on its own; otherwise, your unattended-upgrade invocation may try to act on stale metadata.

Schedule upgrades during low-activity periods when reboots won’t disrupt users or services. For production servers, coordinate the upgrade schedule with monitoring alerts and maintenance windows documented in your runbooks.

Checking Unattended Upgrade Logs

The Unattended-Upgrades package, by default, writes its own log files under /var/log/unattended-upgrades/ in addition to journald entries. Start with the main history log whenever you need to confirm what installed overnight:

sudo tail -f /var/log/unattended-upgrades/unattended-upgrades.log

The companion dpkg log captures the lower-level package operations and is useful when a post-install script fails:

sudo less /var/log/unattended-upgrades/unattended-upgrades-dpkg.log

For a consolidated timeline, query journald directly. Filtering by date or package name is simpler here than grepping syslog:

sudo journalctl -u unattended-upgrades --since "yesterday"

You can narrow the output further, for example sudo journalctl -u unattended-upgrades | grep openssl, to confirm whether a specific package updated. Syslog still records high-level notices, but these dedicated logs provide the detail you need for troubleshooting.

Conclusion

Unattended-upgrades becomes a reliable maintainer when you activate the periodic hooks, restrict the allowed origins thoughtfully, and pair automation with alerts and audit logs. By dialing in 50unattended-upgrades, enforcing least-privilege sudoers rules, scheduling updates after hours, and watching the dedicated log files, you keep Ubuntu patched without sacrificing visibility or operational control.

15 thoughts on “How to Configure Unattended Upgrades on Ubuntu Linux”

  1. A very good explanation of unattended-upgrades.

    This command and comment will not do what is described:

    ” sudo tail -n 50 /var/log/syslog | grep unattended-upgrades

    This command will display the last 50 entries in the syslog file that contain the “unattended-upgrades” keyword.”

    The results will be any entries for unattended-upgrades that appeared in the last 50 lines of syslog.

    To get what the description is describing, the grep operation needs to be applied to the log file, then run the tail command.

    ” sudo grep unattended-upgrades /var/log/syslog | tail -n 50″

    Reply
    • Thanks for catching that, Neil! You’re absolutely right. The original command piped to grep was filtering the last 50 lines of syslog first, which could miss relevant entries if they weren’t in that tail window. Your corrected version (sudo grep unattended-upgrades /var/log/syslog | tail -n 50) properly searches the entire syslog first, then displays the last 50 matching entries.

      I’ve updated the article to prioritize the dedicated log files in /var/log/unattended-upgrades/ (unattended-upgrades.log and unattended-upgrades-dpkg.log) since they provide better signal without needing to grep through general syslog noise. The revised section now uses journalctl for more efficient searching. Appreciate you taking the time to point this out!

      Reply
  2. whatever is responsible for formatting the comments seems to have also changed my posts n dashed to m dashes on post. Tying HTML codes.
    … instead of the double n dashes ( (--) ) …
    e.g. … instead of ” (--)dry-run.

    Reply
  3. The last 4 items of the “Configure Unattended Upgrades” options table have a formatting error (that some editing program probably forced on you) and are currently starting with a longer single m dash (–) instead of the double n dashes (–) the options should be predicated with to be options, e.g. The table has “–dry-run” instead of “–dry-run.”

    Reply
    • Thanks for spotting that, Alexander! You’re right about the dash encoding issue. The WordPress’s visual editor sometimes converts double hyphens into em dashes during paste operations. I’ve reviewed the options table and corrected any instances where --dry-run, --download-only, --minimal-upgrade-steps, and --no-minimal-upgrade-steps were displaying with incorrect dash characters. The commands now show proper double hyphens throughout. Appreciate the sharp eye!

      Reply
    • Exactly right, flederwiesel! Ubuntu has used systemd timers (apt-daily.timer and apt-daily-upgrade.timer) as the default scheduling mechanism since at least 16.04. The article covers this in the “Understanding Automatic Update Scheduling” section, explaining that the systemd timers handle everything automatically after installation. The cron job section is marked as optional and only needed when users want precise control over timing or need to integrate with existing cron-based workflows. Most users should stick with the default systemd timers and skip manual cron configuration entirely.

      Thanks for highlighting this, it’s an important distinction!

      Reply
  4. > This command will display the last 50 entries in the syslog file that contain the “unattended-upgrades” keyword.

    Not true. This command will display from the last 50 entries in the syslog file those that contain the “unattended-upgrades” keyword, which is a subtle difference. 😉

    Did you mean `sudo grep unattended-upgrades /var/log/syslog |tail -n 50`?

    Reply
    • Good catch, flederwiesel! You’re absolutely right about the difference, piping tail output to grep only searches within those last 50 lines, not across the entire log. Your corrected version (sudo grep unattended-upgrades /var/log/syslog | tail -n 50) properly searches the full syslog first, then shows the last 50 matches. I’ve updated the article to prioritize the dedicated log files in /var/log/unattended-upgrades/ and use journalctl for more efficient searching, which avoids this grep/tail ordering issue entirely.

      Thanks for the detailed explanation!

      Reply
    • Hi Josef, that sounds like a graphics driver issue rather than an unattended-upgrades problem. The resolution being locked at 800×600 typically means Ubuntu fell back to generic VESA drivers instead of loading your GPU’s native driver. Try running ubuntu-drivers devices to see what’s available, then sudo ubuntu-drivers autoinstall to install the recommended driver.

      After a reboot, your proper resolution options should return.

      Reply
  5. Hi, there’s a typo in this line, enable is missing the L. Thanks for the guide!

    Enable on boot the unattended services:
    sudo systemctl enabe unattended-upgrades

    Reply

Leave a Comment