Home · About · Services · Industries · Projects · Products · Process · Blog · FAQ · Contact
Monthly server maintenance checklist for Linux servers Our monthly server maintenance checklist for Ubuntu and Debian: patches and reboots, disk and logs, certificates, access review, backups and failed services.
A server that runs for a year without anyone looking at it rarely fails all at once. It fails in small ways first: a disk that creeps from 70% to 95%, a certificate that renewal stopped touching after a DNS change, a former contractor's SSH key still in authorized_keys, a kernel update that was installed months ago but never loaded because nobody rebooted. A monthly pass catches all of those while they are still boring.
The short answer: a monthly server maintenance checklist covers patching and a planned reboot, disk and log growth, certificate expiry, a review of users, keys and open ports, a check that backups restore, failed services and timers, and a written record. On one server it takes about an hour. The value comes from doing it every month.
This is the list we use on Ubuntu and Debian servers, including Docker hosts. The commands are for Ubuntu 24.04 and Debian 12 or 13; we note the RHEL-family equivalents where they differ. Daily alerting and weekly restore tests still matter. This list is for the things monitoring does not tell you about.
Before you start, pick a fixed maintenance window, tell the people who use the system, and take a snapshot or confirm last night's backup before you change anything. On a cloud VM a provider snapshot is the quickest rollback. On bare metal, make sure you can reach the console if the machine does not come back after a reboot. Then open a plain text note for this month's run and fill it in as you go.
1. Patching and the reboot nobody wants to do Unattended upgrades should already be installing security updates daily. The monthly job is to confirm they are actually running, apply everything else, and restart what needs restarting.
# Did unattended-upgrades run, and did it fail?
sudo tail -n 30 /var/log/unattended-upgrades/unattended-upgrades.log
# What is still pending
sudo apt update
apt list --upgradable
# Apply, then see which services are running old libraries
sudo apt full-upgrade
sudo needrestart -r l
# Ubuntu: is a reboot required (new kernel, libc and similar)?
[ -f /var/run/reboot-required ] && cat /var/run/reboot-required.pkgs
# Running kernel vs installed kernels
uname -r
dpkg --list 'linux-image-*' | grep ^iiOn Debian the reboot-required flag is not always written, so rely on needrestart's kernel check or compare uname -r with the installed kernels. If the running kernel is older than the newest installed one, the security fixes in that kernel are not protecting you yet. Reboot inside the window and confirm everything comes back on its own: containers with a restart policy, systemd services enabled, mounts present. A reboot that needs a human to start the database is a problem you want to find on a quiet Tuesday, not during an outage. On RHEL, Rocky or Alma, use dnf check-update and dnf needs-restarting -r for the same checks.
Once a month is also when we glance at the operating system's support dates. Ubuntu 20.04 left standard support in May 2025, 22.04 follows in 2027, and Debian 12 moved from regular security support to LTS in mid-2026. Plan the upgrade a few months ahead rather than discovering one day that apt has nothing new to offer.
2. Disk, inodes and logs Full disks cause more outages on small servers than anything clever. Check space and inodes, then find what is growing.
df -h -x tmpfs -x devtmpfs
df -i -x tmpfs -x devtmpfs | sort -k5 -n | tail -5
# Biggest directories on the root filesystem
sudo du -xh / --max-depth=2 2>/dev/null | sort -h | tail -15
# systemd journal size, and cap it
journalctl --disk-usage
sudo journalctl --vacuum-time=30d
# Docker hosts
docker system dfThe usual culprits are the journal, application logs without rotation, old Docker images from every deploy, container logs using the default json-file driver with no size limit, and local backup files that were meant to be copied off and deleted. Fix the cause, not just the symptom: set SystemMaxUse in /etc/systemd/journald.conf, add a logrotate rule, configure max-size and max-file for container logs in /etc/docker/daemon.json (it only applies to containers created after the change, so recreate them). Write down the used percentage each month. A disk that grew 4% per month for three months tells you when to resize.
3. Certificates and domains Certificate lifetimes are getting shorter. The CA/Browser Forum cut the maximum lifetime of public TLS certificates to 200 days from March 2026, falling to 100 days in 2027 and 47 days in 2029. Let's Encrypt also stopped sending expiry reminder emails in 2025. Automatic renewal is now the only sensible option, so the monthly job is to check it is still working for every hostname.
# Expiry date of what a hostname is actually serving
for h in example.com api.example.com; do
printf '%s ' "$h"
echo | openssl s_client -connect "$h:443" -servername "$h" 2>/dev/null \
| openssl x509 -noout -enddate
done
# Certbot: rehearse renewal without issuing anything
sudo certbot renew --dry-runCheck what the server presents, not only the files on disk. A renewed certificate does nothing if NGINX was never reloaded. If you use Traefik or Caddy, look for ACME errors in their logs instead. Wildcard certificates that rely on a DNS challenge break quietly when someone rotates the DNS provider's API token, so test those explicitly. While you are there, check the domain registration expiry dates.
4. Access: users, keys, ports and firewall Access drifts. People leave, contractors finish, a port gets opened for a quick test and stays open. Review it every month against a list of who should have access.
# Accounts that can log in
awk -F: '$7 !~ /(nologin|false)$/ {print $1, $6, $7}' /etc/passwd
# Who has sudo
getent group sudo
# Every authorized_keys file and its key count
sudo find /root /home -name authorized_keys -exec sh -c 'echo "$1: $(grep -c . "$1")"' _ {} \;
# Recent logins
last -n 20
# What is listening, and what the firewall allows
sudo ss -tulpn
sudo ufw status numberedRemove keys you cannot match to a current person or system. A key with no comment is a key nobody can account for. Confirm the effective SSH settings with sudo sshd -T | grep -Ei '^(passwordauthentication|permitrootlogin)'. You want passwordauthentication no and permitrootlogin no or prohibit-password. Anything listening on 0.0.0.0 that is not your web server or SSH needs a reason. Databases, Redis and admin panels should be on localhost or a private network such as Tailscale. Remember that Docker publishes ports by writing its own iptables rules, which bypass ufw. Check ss output, not just the firewall rules. Rotate shared credentials that a departed person knew: database passwords, API tokens in environment files, the backup storage key. 5. Backups, services and the clock Confirm the newest backup in off-site storage is from last night and roughly the size you expect, and that the last scheduled restore test passed. If you do not have a restore test, this is the month to set one up. Then look for things that failed silently.
# Units that have failed since boot
systemctl --failed
# Timers, with last and next run
systemctl list-timers --all
# Containers that are restarting or exited
docker ps -a --filter status=exited --filter status=restarting
# Clock in sync (TLS, logs and tokens depend on it)
timedatectl status | grep -i synchronized
# Bare metal only: disk health (use /dev/nvme0 for NVMe drives)
sudo smartctl -H /dev/sdaA timer that shows n/a in the LAST column has not run since boot, or ever. A container stuck in a restart loop may not trip an HTTP check if another replica answers. On physical servers, SMART warnings and RAID status deserve a look every month, because a degraded array works fine until the second disk goes.
6. Write it down The record is what turns a checklist into maintenance. For each server, keep a short entry: date, updates applied, whether it rebooted, disk usage, nearest certificate expiry, access changes, and anything deferred with a reason. It takes five minutes and gives you trends, an audit trail when someone asks who removed a key, and a handover document if the person who usually does this is away.
Over time, move repetitive checks into automation. Certificate expiry, disk percentage and failed units are easy to alert on. Keep the human pass for judgement: whether a key still belongs, whether a port should be open, whether a growing disk is normal.
The checklist Snapshot or confirm a recent backup before changes. Check unattended-upgrades ran; apply pending updates; run needrestart. Reboot if the kernel or core libraries changed; confirm every service starts unaided. Note OS end-of-support dates and plan upgrades early. Record disk and inode usage; clean logs, old images and stray dumps; fix rotation. Check served certificate expiry for every hostname; dry-run renewal; check domain expiry. Review login accounts, sudo members, authorized_keys and departed staff. Compare listening ports with what should be exposed, including Docker-published ports. Confirm last night's off-site backup and the last restore test. Check failed units, timers, exited containers, time sync and disk health. Write the monthly record and list anything deferred. If the pass keeps turning up the same problems, or nobody owns the servers enough to do it every month, that is the point to get help. Either hand the routine to someone with agreed hours and response times, or spend a day fixing the root causes so the monthly hour stays an hour.
Infigini IT Services · 11 Kanwali Road, Dehradun 248001, India · info@infigini.com · +91 95684 87789