By the end of this guide you'll have a Linux server that installs its own security patches without you logging in to do it by hand. We'll cover Debian and Ubuntu with unattended-upgrades, the Red Hat family (Fedora, Rocky, AlmaLinux, RHEL) with dnf-automatic, automatic reboots for kernel patches, and how to confirm the whole thing is actually working. It's written for anyone who runs a server, whether that's a game server, a website, a Discord bot, or a small VPS, and you don't need to be a Linux expert to follow along.
Why this matters more than you'd think
Most servers that get compromised aren't hit by some clever zero day attack. They get hit because a known bug sat unpatched for weeks or months. Someone published the fix, the bad guys read the same changelog, and they went looking for machines that never applied it. A server that patches itself closes that window fast.
The catch is that updates can occasionally break things. So the goal here isn't to blindly install everything the moment it ships. It's to install security patches automatically and quickly, while being a bit more careful with the rest. That's the balance we run on our own boxes, and it's the setup we'll build below.
One thing before you start. Take a backup or a snapshot first. If your host gives you snapshots (most VPS providers do), grab one now. That way if a patch ever does cause trouble, you can roll back in minutes instead of debugging at 2am.
Debian and Ubuntu with unattended-upgrades
Debian and Ubuntu use the same tool, called unattended-upgrades. It hooks into apt and runs on a timer. Let's install it and turn it on.
Step 1: Install the packages
Update your package list and install the tool. The apt-listchanges package is optional but handy, since it can summarize what changed.
sudo apt update
sudo apt install unattended-upgrades apt-listchanges
On a fresh Ubuntu install, unattended-upgrades is often already present. Installing it again does no harm, so run the command anyway to be sure.
Step 2: Enable it
There's a built in helper that flips the right switches for you. Run it and choose Yes when the blue dialog asks whether to download and install stable updates automatically.
sudo dpkg-reconfigure --priority=low unattended-upgrades
This writes a small file at /etc/apt/apt.conf.d/20auto-upgrades. You can check it, and if you ever want to skip the dialog, you can create the file yourself with these two lines:
cat /etc/apt/apt.conf.d/20auto-upgrades
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
The first line tells apt to refresh its package list once a day. The second tells it to run unattended-upgrades once a day. The value "1" means every day. If you set it to "7" it would run weekly, but daily is what you want for security fixes.
Step 3: Tune what gets installed
The main config lives in /etc/apt/apt.conf.d/50unattended-upgrades. Open it with your editor of choice.
sudo nano /etc/apt/apt.conf.d/50unattended-upgrades
Near the top you'll find an Allowed-Origins (or on newer Ubuntu, Origins-Pattern) block. This decides which repositories the tool is allowed to pull from. The default on Ubuntu keeps the security line active and comments out the rest. That's exactly what we want for a careful setup. Here's roughly what it looks like on Ubuntu:
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";
};
The lines that start with // are switched off. If you want security only updates, leave -updates commented out. That's the safer choice for a production game server or website, since regular updates are more likely to change behavior. If you'd rather pull all updates, remove the // in front of the -updates line. Don't enable -proposed; that's a testing channel and it can ship half baked packages.
On Debian the origin names are slightly different. Look for entries referencing Debian-Security and make sure that one is active:
Unattended-Upgrade::Origins-Pattern {
"origin=Debian,codename=${distro_codename},label=Debian-Security";
"origin=Debian,codename=${distro_codename}-security,label=Debian-Security";
};
Step 4: Set up automatic reboots for kernel patches
Some patches, especially kernel ones, only take effect after a reboot. By default the server installs them but waits for you to reboot manually. If you want it to handle that too, find these lines in the same 50unattended-upgrades file and edit them. They're usually present but commented out.
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-WithUsers "true";
Unattended-Upgrade::Automatic-Reboot-Time "04:00";
The first line turns reboots on. The third picks a quiet time, here 4am server time, so players or visitors aren't kicked off in the middle of the day. Pick an hour that's slow for your service. If your server runs something that really should never restart on its own, leave Automatic-Reboot as "false" and reboot yourself on a schedule you control.
A couple of other lines are worth setting while you're in there. These tell the tool to email you if something goes wrong, and to clean up old downloaded packages so the disk doesn't fill up:
Unattended-Upgrade::Mail "[email protected]";
Unattended-Upgrade::MailReport "on-change";
Unattended-Upgrade::Remove-Unused-Dependencies "true";
The mail lines need a working mail setup on the box (something like postfix or msmtp). If you don't have mail configured, skip those two lines for now. The logs will still record everything.
Step 5: Test it without waiting a day
You don't have to wait for the timer to find out if your config is sane. Run a dry run. This goes through the motions and tells you what it would install, without actually changing anything.
sudo unattended-upgrade --dry-run --debug
You'll see output listing the origins it checked and which packages match. If it prints something like "No packages found that can be upgraded unattended" and no errors, your config is valid and there's just nothing to do right now. If you see a clear list of packages and a clean exit, you're good.
To actually run it once by hand, drop the --dry-run flag:
sudo unattended-upgrade --debug
Fedora, Rocky, AlmaLinux and RHEL with dnf-automatic
The Red Hat family doesn't use apt. It uses dnf, and the automatic update tool is dnf-automatic. The idea is the same, but the files and commands differ.
Step 1: Install it
sudo dnf install dnf-automatic
Step 2: Configure security only or everything
The config file is /etc/dnf/automatic.conf. Open it up.
sudo nano /etc/dnf/automatic.conf
Two settings matter most. In the [commands] section, upgrade_type chooses what to install and apply_updates decides whether it installs them or just downloads them. For a security focused setup, use this:
[commands]
upgrade_type = security
download_updates = yes
apply_updates = yes
Setting upgrade_type = security limits it to security advisories. If you want every available update instead, change that to default. If you'd rather it only downloads patches and lets you apply them yourself, set apply_updates = no and you'll just get a notification. While you're in the file, the [emitters] section controls how you're notified. To get an email, set emit_via = email and fill in the email_from and email_to values.
Step 3: Turn on the timer
dnf-automatic runs through a systemd timer. Enable and start it so it fires on schedule and survives a reboot.
sudo systemctl enable --now dnf-automatic.timer
Confirm the timer is active and see when it's due to run next:
systemctl list-timers dnf-automatic.timer
You should see a line with a NEXT time and the timer marked active. By default it runs roughly once a day.
Step 4: Run it once to check
You can trigger the service immediately rather than waiting for the timer. This actually applies updates based on your config, so only run it when you're ready.
sudo systemctl start dnf-automatic.service
A note on reboots for the Red Hat family. dnf-automatic itself won't reboot the machine. If you want automatic reboots after a kernel update, the clean way is the dnf-automatic-restart approach or a small tool called needs-restarting, which ships with dnf-utils. You can check whether a reboot is needed at any time with:
sudo needs-restarting -r
If it says a reboot is required, schedule one for a quiet hour. Many admins pair this with a cron job that reboots in the early morning only when needed.
Confirm it actually ran
Setting this up and then never checking is how people get a false sense of safety. Verify it. On Debian and Ubuntu, the logs live in a dedicated folder. The main one tells you what was installed and when:
cat /var/log/unattended-upgrades/unattended-upgrades.log
You can also confirm the systemd timer that drives it is healthy:
systemctl status apt-daily-upgrade.timer
systemctl list-timers | grep apt
On the Red Hat side, check the journal for the service. This shows the last few runs and any errors:
journalctl -u dnf-automatic.service --since "-7 days"
If you ever want a quick look at what security updates are currently pending on a Red Hat box, that's a one liner too:
dnf updateinfo list security
Reducing the risk that an update breaks something
Automatic patching is a big net win, but a small number of updates do cause problems. Here's how we keep the risk low without giving up the benefit.
- Stick to security only on critical machines. The security channel is small and tightly tested. General updates change far more.
- Take snapshots. If your VPS host offers daily or pre update snapshots, use them. Rollback beats debugging.
- Hold packages you really care about. If a specific package version is load bearing for your app, you can pin it so updates skip it. On apt that's
sudo apt-mark hold packagename, and to release it later,sudo apt-mark unhold packagename. On dnf you add anexclude=packagenameline under[main]in/etc/dnf/dnf.conf. - Pick a sane reboot window. A 4am reboot during a low traffic window is far less painful than a surprise restart during peak hours.
- Read the email reports. If you set up mail, skim the change summaries now and then. You'll spot anything unusual before it bites.
If you host a game server or anything player facing, like the Minecraft and game hosting we run at Bytte.cloud, lean toward security only patches plus a scheduled off peak reboot. Players notice a restart far more than they notice a quietly applied patch.
Troubleshooting
Updates aren't being applied
First, confirm the master switch is on. On Debian and Ubuntu, check /etc/apt/apt.conf.d/20auto-upgrades and make sure both lines read "1". A common mistake is that APT::Periodic::Unattended-Upgrade is set to "0". Then run the dry run, sudo unattended-upgrade --dry-run --debug, and read the output. It almost always tells you why a package was skipped. On Red Hat, run systemctl list-timers dnf-automatic.timer to be sure the timer is enabled, and check the journal for errors.
Some packages are held back
If you run a manual update and see "The following packages have been kept back," it usually means a package needs a new dependency that unattended-upgrades won't pull in on its own, often a phased rollout or a kernel package. That's normal and intentional. Security patches still flow. If you want to push the held back package through manually, run sudo apt full-upgrade at a time you're watching the server, not unattended.
The server rebooted when I didn't expect it
That's the automatic reboot setting doing its job. Open /etc/apt/apt.conf.d/50unattended-upgrades and check Unattended-Upgrade::Automatic-Reboot. Set it to "false" if you'd rather handle reboots yourself, or change Automatic-Reboot-Time to a quieter hour.
The disk filled up with old packages
Downloaded package archives can pile up. Clear them and let the tool prune automatically going forward by setting Unattended-Upgrade::Remove-Unused-Dependencies "true". To clean up right now on apt, run sudo apt autoremove and sudo apt clean. On dnf, sudo dnf clean packages does the same job.
Mail reports never arrive
The mail options only work if the server can actually send mail. If nothing shows up, you probably don't have an MTA installed or configured. Either set up a lightweight sender like msmtp, or drop the mail lines and rely on the logs instead. The patching still happens regardless; you just won't get the email.
"E: Could not get lock" errors
This means another apt process is already running, often the automatic update itself or the package list refresh. Wait a minute and try again. If it persists, find the process with ps aux | grep -i apt and let it finish rather than killing it midway, which can leave the package database in a bad state.
Wrapping up
You've now got a server that quietly keeps itself patched. On Debian and Ubuntu that's unattended-upgrades pulling the security channel daily, on the Red Hat family it's dnf-automatic on a systemd timer, and on both you've got a sensible reboot window and a way to read the logs. Set it once, check the logs a week later to confirm it's working, and then mostly forget about it. The few minutes you spent here saves you from being the easy target that gets caught by a months old bug. If you run anything important, pair this with regular snapshots and you've covered the two things that matter most: staying patched and being able to roll back.



