Automatic Security Updates on VPS: Unattended Upgrades, Alerts, and Safe Automation
Unpatched packages are one of the most common causes of VPS compromise β many attacks exploit known vulnerabilities with published CVEs and public exploit code. Running outdated software for days or weeks after a security patch is released leaves your server exposed to automated scanning and exploitation. Ubuntu’s unattended-upgrades package automates security patching, applying updates as soon as they’re released without manual intervention.
What Unattended Upgrades Does
- Applies security updates automatically: Only from Ubuntu Security (ubuntu-security) and Ubuntu Updates repositories by default
- Does NOT auto-update all packages: Only security-classified packages, not general updates (which might break compatibility)
- Sends email reports: What was updated, any errors
- Optional automatic reboot: For kernel updates that require a restart (configurable)
Step 1: Install and Enable
<code"># Install unattended-upgrades (usually pre-installed on Ubuntu) sudo apt install -y unattended-upgrades apt-listchanges # Enable automatic updates sudo dpkg-reconfigure -plow unattended-upgrades # Answer "Yes" when prompted # Or enable directly: cat | sudo tee /etc/apt/apt.conf.d/20auto-upgrades << 'EOF' APT::Periodic::Update-Package-Lists "1"; // Check for updates daily APT::Periodic::Unattended-Upgrade "1"; // Apply updates daily APT::Periodic::AutocleanInterval "7"; // Clean package cache weekly APT::Periodic::Download-Upgradeable-Packages "1"; // Download before applying EOF
Step 2: Configure What Gets Updated
<code">sudo nano /etc/apt/apt.conf.d/50unattended-upgrades
<code">Unattended-Upgrade::Allowed-Origins {
// Ubuntu security updates β always enable
"${distro_id}:${distro_codename}-security";
"${distro_id}ESMApps:${distro_codename}-apps-security";
"${distro_id}ESM:${distro_codename}-infra-security";
// Optional: Also apply general updates (more risk, more coverage)
// "${distro_id}:${distro_codename}";
// "${distro_id}:${distro_codename}-updates";
};
// Packages to NEVER auto-update (add packages that need manual testing)
Unattended-Upgrade::Package-Blacklist {
// "nginx"; // Example: don't auto-update Nginx config-sensitive packages
// "postgresql-16"; // Example: major DB updates need manual migration check
};
// Remove unused dependencies automatically
Unattended-Upgrade::Remove-Unused-Dependencies "true";
Unattended-Upgrade::Remove-New-Unused-Dependencies "true";
// Email configuration
Unattended-Upgrade::Mail "admin@yourdomain.com";
Unattended-Upgrade::MailReport "on-change"; // "always", "on-change", "only-on-error"
// Automatic reboot for kernel updates
Unattended-Upgrade::Automatic-Reboot "false"; // Change to "true" to auto-reboot
Unattended-Upgrade::Automatic-Reboot-Time "04:00"; // If rebooting, do it at 4 AM
// Minimal logging (set to "1" for verbose)
Unattended-Upgrade::Verbose "0";
// Only download, don't apply (for manual review):
// Unattended-Upgrade::InstallOnShutdown "false";
Step 3: Configure Email Notifications
<code"># Install msmtp for lightweight SMTP relay sudo apt install -y msmtp msmtp-mta sudo nano /etc/msmtprc
<code">defaults auth on tls on tls_trust_file /etc/ssl/certs/ca-certificates.crt logfile /var/log/msmtp.log account default host smtp.mailgun.org port 587 from vps-alerts@yourdomain.com user postmaster@mg.yourdomain.com password your_mailgun_password account default : default
<code">sudo chmod 600 /etc/msmtprc # Test email echo "Test from VPS" | mail -s "Test Alert" admin@yourdomain.com # Check if unattended-upgrades uses the right mailer: sudo nano /etc/apt/apt.conf.d/50unattended-upgrades # Ensure: Unattended-Upgrade::Mail "admin@yourdomain.com";
Step 4: Telegram Notifications (More Reliable Than Email)
<code">sudo nano /usr/local/bin/notify-updates.sh
<code">#!/bin/bash
# Send Telegram notification when unattended-upgrades runs
BOT_TOKEN="YOUR_TELEGRAM_BOT_TOKEN"
CHAT_ID="YOUR_TELEGRAM_CHAT_ID"
LOG="/var/log/unattended-upgrades/unattended-upgrades.log"
HOSTNAME=$(hostname)
# Check if any upgrades were applied today
TODAY=$(date +%Y-%m-%d)
UPDATES=$(grep -c "Upgraded:" "$LOG" 2>/dev/null || echo 0)
ERRORS=$(grep -c "ERROR" "$LOG" 2>/dev/null || echo 0)
if [ "$UPDATES" -gt 0 ] || [ "$ERRORS" -gt 0 ]; then
PACKAGES=$(grep "Upgraded:" "$LOG" | tail -5 | sed 's/.*Upgraded: //')
MESSAGE="π *Security Updates Applied*
Host: \`$HOSTNAME\`
Date: $TODAY
Packages updated: $UPDATES
$([ "$ERRORS" -gt 0 ] && echo "β οΈ Errors: $ERRORS" || echo "β
No errors")
Recent: $PACKAGES"
curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
-d "chat_id=${CHAT_ID}" \
-d "parse_mode=Markdown" \
-d "text=${MESSAGE}" > /dev/null
fi
<code">chmod +x /usr/local/bin/notify-updates.sh
# Schedule to run after unattended-upgrades (6 AM daily)
echo "0 6 * * * root /usr/local/bin/notify-updates.sh" | \
sudo tee /etc/cron.d/update-notifications
Step 5: Manual Testing
<code"># Dry run β see what WOULD be updated without applying
sudo unattended-upgrades --dry-run --verbose
# Force run immediately (applies updates now)
sudo unattended-upgrades --verbose
# Check what was applied
cat /var/log/unattended-upgrades/unattended-upgrades.log | tail -30
# Check for pending kernel reboot
if [ -f /var/run/reboot-required ]; then
echo "REBOOT REQUIRED"
cat /var/run/reboot-required.pkgs
fi
Step 6: Kernel Updates and Reboots
<code"># Kernel security updates are applied but require reboot to take effect
# Check if reboot is needed:
cat /var/run/reboot-required 2>/dev/null && echo "Reboot needed" || echo "No reboot needed"
cat /var/run/reboot-required.pkgs 2>/dev/null # Which packages need reboot
# Use kexec for faster kernel updates (no BIOS/GRUB wait):
sudo apt install -y kexec-tools
# Or use livepatch for kernel updates without reboots (Ubuntu Pro feature):
sudo ua enable livepatch # Requires Ubuntu Pro (free for 5 machines)
# Schedule reboots safely with prior notice:
# Add to cron β reboot at 4 AM if update requires it:
echo "0 4 * * * root [ -f /var/run/reboot-required ] && /sbin/shutdown -r now 'Scheduled reboot for kernel update'" | \
sudo tee /etc/cron.d/reboot-if-required
Step 7: Exclude Docker Packages
<code"># Docker packages should NOT be auto-updated β they can change container runtime
# behavior and break running containers
# Add to /etc/apt/apt.conf.d/50unattended-upgrades:
Unattended-Upgrade::Package-Blacklist {
"docker-ce";
"docker-ce-cli";
"containerd.io";
"docker-compose-plugin";
// Also exclude packages that need migration steps:
// "postgresql-*";
};
Getting Started
Unattended upgrades should be enabled on every VPS immediately after provisioning β before installing any other software. On Ubuntu VPS plans at VPS.DO, Ubuntu Security releases security patches within hours of upstream disclosure. Automated patching with Telegram notifications gives you the best of both worlds: security without manual monitoring, with immediate notification when patches are applied.
Conclusion
Automatic security updates with unattended-upgrades are the single highest-ROI security improvement for a VPS β eliminating the most common attack vector (known, patched vulnerabilities) with zero daily effort. Configure it to update only security-classified packages, exclude packages that need manual migration (Docker, PostgreSQL major versions), send Telegram notifications when patches apply, and add a Telegram alert for when a kernel reboot is pending. Combined with SSH key auth, UFW, and Fail2ban, automated patching completes a solid VPS security baseline.