Most of the small-business Linux servers I’ve been called in to clean up had the same problem: nobody had touched them since they were set up. The site was running, the LAMP stack was responding, and the kernel was four years out of date with a long list of unpatched CVEs sitting in the background. The XZ backdoor (CVE-2024-3094) in 2024 was the most public recent example of what happens when this catches up to people, but it’s the same story every year.
The fix isn’t willpower. Nobody is going to remember to SSH in every Tuesday to run apt update. The fix is config. Here’s what I actually set up on every Droplet I manage.
unattended-upgrades for security patches
Ubuntu (and Debian) ship a package that, when configured properly, applies security updates automatically every night. Install and configure:
sudo apt install unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades
Then edit /etc/apt/apt.conf.d/50unattended-upgrades and make sure the security origin is uncommented. On Ubuntu LTS this is the line that includes ${distro_codename}-security. Then in /etc/apt/apt.conf.d/20auto-upgrades:
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::AutocleanInterval "7";
This handles the bulk of the threat surface. Verify it’s actually running with cat /var/log/unattended-upgrades/unattended-upgrades.log.
Reboots: the part you can’t fully automate
Most security patches apply without a reboot. Kernel and certain library updates don’t. The file /var/run/reboot-required appears when one is needed. My rule: any server I manage gets a manual reboot inside 48 hours of that file appearing, scheduled for off-hours.
You can fully automate this with the Unattended-Upgrade::Automatic-Reboot directive, and for most workloads (single-WordPress, FusionInvoice, Nextcloud) that’s fine. For anything with multi-step session state, I prefer to do it by hand so I can confirm the app comes back cleanly.
Application-level patches
The OS is the easy part. The application stack on top is where most actual breaches come from. The 2020 WP File Manager plugin RCE, the constant churn of WordPress plugin vulnerabilities, every PHP framework that’s ever shipped an unsafe deserialization bug. A few things help:
- WordPress: enable auto-updates for minor releases and plugins via the WP admin or by setting
WP_AUTO_UPDATE_COREinwp-config.php. Major core updates I do manually after taking a backup. - Laravel apps (FusionInvoice, custom): watch for new releases. Updates are usually
git pull+composer install --no-dev+php artisan migrate, and take 5 minutes. - Docker-based deploys: use a tag like
:latestonly if you have a way to roll back, otherwise pin to a specific tag and bump it deliberately. Watchtower is fine for low-stakes deployments.
Lightweight monitoring so you know when something breaks
For solo-managed servers I don’t reach for Datadog or Prometheus. Overkill and overpriced. What I actually run:
- Uptime Kuma on a separate small Droplet, pinging each managed server’s public URL every minute. Free, self-hosted, and notifies via email, Telegram, or webhook.
- DigitalOcean’s built-in monitoring agent for disk, CPU, and memory alerts. It’s free with every Droplet and you just enable it.
- A nightly cron that pipes
apt list --upgradableanduptimeinto an email to me. Ugly, but I know within 24 hours if a server stopped patching.
The thing that catches almost everything else: backups
If patching fails or an app gets compromised, the question is how quickly you can get back to a known-good state. DigitalOcean’s weekly backup add-on is $1.20/month per Droplet and gives you a 7-day rolling window of images. Pair that with database dumps to DigitalOcean Spaces (or another off-host location) on a daily cron, and the worst-case recovery is “restore from yesterday.”
If you want me to run this for you
Tiempo manages this stack across a handful of client Droplets on a monthly retainer. Patches go on, kernels get rebooted on schedule, app updates get applied, you don’t think about any of it. Get in touch if you’re tired of the “wait, when’s the last time we updated that server” conversation.