
Your VPS rarely fails from one big incident. It usually degrades from small misses that stack up.
Common examples: a kernel update waiting on a reboot, logs quietly consuming disk, a stuck service nobody spotted, or backups nobody has tested in months.
This linux server maintenance tutorial shows how to automate the boring parts while keeping change controlled and auditable.
The examples target Ubuntu Server 24.04 LTS and Debian 12/13-style layouts. The pattern works on most Linux hosting servers.
You’ll set a predictable cadence with systemd timers. You’ll apply unattended security updates on your schedule. You’ll reboot only when required, cap log growth, and keep a quick “is this box healthy?” routine you can run in under two minutes.
What you’ll build (and why it matters for hosting)
- Automatic security patching with an audit trail you can actually read (what changed, when).
- Planned reboots only when they’re needed, inside a window you choose.
- Disk pressure prevention using log rotation, journald limits, and conservative cleanup.
- Service health checks with quick diagnostics for web + mail + SSH basics.
- Maintenance notifications so changes don’t surprise you.
If you run production sites, do this on a VPS or dedicated server where you control packages and reboots.
If you’d rather offload routine upkeep while keeping visibility, managed VPS hosting from HostMyCode can handle patch cadence and basic checks while you still keep admin access.
Prerequisites and a safe starting point
Before you automate anything, make sure recovery is real—not theoretical. At minimum, have:
- Root or sudo access
- SSH key access (not password-only)
- Known-good backups (plus at least one restore test)
- A maintenance window (even 15 minutes weekly is enough)
If backups aren’t solid, fix that first.
HostMyCode also offers migration help and recovery planning via migrations. This is handy if you’re moving from shared hosting to a VPS and want a controlled cutover.
Quick inventory commands (copy/paste):
lsb_release -a 2>/dev/null || cat /etc/os-release
uname -r
uptime
df -hT
free -h
systemctl --failed
ss -tulpen | head -n 40
Step 1 — Create a maintenance window and change log
Automation behaves better when it has a schedule. Pick a weekly window where brief restarts won’t hurt.
Something like “Sunday 03:00–03:30” is plenty.
Next, create a simple local change log. You should be able to answer “What happened overnight?” without digging through five different logs.
sudo install -d -m 0755 /var/log/maintenance
sudo touch /var/log/maintenance/changes.log
sudo chmod 0644 /var/log/maintenance/changes.log
Later steps will append to this file from timers and scripts.
Step 2 — Enable unattended security updates (but keep them predictable)
On hosting servers, unattended upgrades should cover security updates automatically. Keep feature upgrades and distro jumps manual.
Ubuntu:
sudo apt update
sudo apt install -y unattended-upgrades apt-listchanges
sudo dpkg-reconfigure --priority=low unattended-upgrades
Debian (same idea):
sudo apt update
sudo apt install -y unattended-upgrades apt-listchanges
sudo dpkg-reconfigure --priority=low unattended-upgrades
Verify these configuration files:
/etc/apt/apt.conf.d/50unattended-upgrades/etc/apt/apt.conf.d/20auto-upgrades
Baseline settings (adjust to taste). In /etc/apt/apt.conf.d/20auto-upgrades:
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::AutocleanInterval "7";
Audit trail tip: unattended-upgrades writes to /var/log/unattended-upgrades/. Use that directory to confirm what was patched.
Common pitfall: automatic updates can restart services (PHP-FPM is a classic) at awkward times.
This usually happens when you don’t control timing. The next step fixes that.
Step 3 — Schedule updates with systemd timers (so you choose the time)
On systemd-based distros, the apt periodic jobs already exist. Don’t invent new cron jobs.
Instead, override the timers so they run during your maintenance window.
Inspect current timers:
systemctl list-timers --all | egrep 'apt|unattended|fstrim|logrotate' || true
On Ubuntu, you’ll typically see apt-daily.timer and apt-daily-upgrade.timer.
Create an override for apt-daily-upgrade.timer so upgrades run when you expect them to. Example: Sundays at 03:10.
sudo systemctl edit apt-daily-upgrade.timer
Add:
[Timer]
OnCalendar=
OnCalendar=Sun *-*-* 03:10:00
RandomizedDelaySec=0
Persistent=true
Reload and confirm:
sudo systemctl daemon-reload
sudo systemctl restart apt-daily-upgrade.timer
systemctl status apt-daily-upgrade.timer --no-pager
systemctl list-timers apt-daily-upgrade.timer
If you want, do the same for apt-daily.timer
Many admins leave it daily because it’s low impact.
Optional: append a line to your change log after upgrades.
Create a small script:
sudo tee /usr/local/sbin/maintenance-log-apt.sh >/dev/null <<'EOF'
#!/bin/sh
set -eu
STAMP="$(date -Is)"
LOG="/var/log/maintenance/changes.log"
LAST="/var/log/unattended-upgrades/unattended-upgrades.log"
{
echo "[$STAMP] apt-daily-upgrade completed"
if [ -f "$LAST" ]; then
tail -n 30 "$LAST" | sed 's/^/ /'
fi
echo ""
} >> "$LOG"
EOF
sudo chmod 0755 /usr/local/sbin/maintenance-log-apt.sh
Then add a drop-in so the service runs it. This keeps the change clean and easy to remove later.
Create:
sudo systemctl edit apt-daily-upgrade.service
Add:
[Service]
ExecStartPost=/usr/local/sbin/maintenance-log-apt.sh
Reload:
sudo systemctl daemon-reload
Step 4 — Handle “reboot required” safely (without surprise downtime)
Kernel and libc updates often need a reboot. The bad options are never rebooting (risk accumulates) or rebooting immediately (unplanned downtime).
The workable option is a controlled reboot inside your window.
Check if a reboot is required:
if [ -f /var/run/reboot-required ]; then
echo "Reboot required";
cat /var/run/reboot-required.pkgs || true
else
echo "No reboot required";
fi
Practical approach for hosting servers:
- Only reboot inside the maintenance window.
- Log it (and notify yourself, if you can).
- Give services a chance to shut down cleanly where it matters.
Create a reboot-if-needed script. It should only reboot when /var/run/reboot-required exists:
sudo tee /usr/local/sbin/reboot-if-required.sh >/dev/null <<'EOF'
#!/bin/sh
set -eu
LOG="/var/log/maintenance/changes.log"
STAMP="$(date -Is)"
if [ -f /var/run/reboot-required ]; then
echo "[$STAMP] reboot-required detected; rebooting now" >> "$LOG"
shutdown -r +1 "Planned maintenance reboot (security updates)"
else
echo "[$STAMP] no reboot required" >> "$LOG"
fi
EOF
sudo chmod 0755 /usr/local/sbin/reboot-if-required.sh
Schedule it as a weekly systemd timer right after upgrades.
Create a service:
sudo tee /etc/systemd/system/reboot-if-required.service >/dev/null <<'EOF'
[Unit]
Description=Reboot the server if /var/run/reboot-required exists
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/reboot-if-required.sh
EOF
Create a timer (Sundays at 03:20):
sudo tee /etc/systemd/system/reboot-if-required.timer >/dev/null <<'EOF'
[Unit]
Description=Weekly reboot check after maintenance updates
[Timer]
OnCalendar=Sun *-*-* 03:20:00
Persistent=true
[Install]
WantedBy=timers.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now reboot-if-required.timer
systemctl list-timers reboot-if-required.timer
For cPanel/WHM servers: reboots still matter, but you’ll also want EasyApache and service restarts coordinated.
If you operate WHM, pair this with your hardening work from: cPanel hardening tutorial.
Step 5 — Put hard limits on logs (journald + logrotate)
Disk-full incidents cause a lot of “mysterious downtime” on VPS hosting.
Two repeat offenders show up again and again: systemd journal growth and chatty application logs.
Limit systemd journal size
Edit /etc/systemd/journald.conf and set explicit caps:
sudo nano /etc/systemd/journald.conf
Recommended baseline:
[Journal]
SystemMaxUse=1G
SystemKeepFree=2G
MaxRetentionSec=14day
Compress=yes
Apply:
sudo systemctl restart systemd-journald
journalctl --disk-usage
Verify logrotate is working
Logrotate usually runs daily via timer/cron. Confirm what’s in place:
ls -l /etc/logrotate.conf /etc/logrotate.d/
logrotate --debug /etc/logrotate.conf | head -n 60
Force a run (safe: with sane config, it rotates rather than truncating blindly):
sudo logrotate -f /etc/logrotate.conf
Pitfall: custom app logs under /var/www/ often aren’t covered.
If you run Node/Python behind Nginx, move logs under /var/log/ and add a logrotate stanza.
If you want a structured approach (especially on multi-site VPS nodes), pair this with: VPS log auditing with rsyslog + logrotate.
Step 6 — Automate disk and temp cleanup (without deleting what you need)
Keep cleanup conservative. The goal isn’t “optimization.” It’s avoiding preventable outages.
Create a weekly cleanup script that:
- cleans apt cache
- removes old crash reports
- removes old temp files (only those untouched for days)
sudo tee /usr/local/sbin/weekly-cleanup.sh >/dev/null <<'EOF'
#!/bin/sh
set -eu
LOG="/var/log/maintenance/changes.log"
STAMP="$(date -Is)"
{
echo "[$STAMP] weekly cleanup starting"
apt-get -y autoclean || true
apt-get -y autoremove --purge || true
# Ubuntu crash reports (safe to remove if you don't use apport)
rm -f /var/crash/* 2>/dev/null || true
# Conservative temp cleanup: only files not modified in 7 days
find /tmp -type f -mtime +7 -delete 2>/dev/null || true
echo "[$STAMP] weekly cleanup done"
echo ""
} >> "$LOG"
EOF
sudo chmod 0755 /usr/local/sbin/weekly-cleanup.sh
Schedule it (Sundays at 03:05, before upgrades):
sudo tee /etc/systemd/system/weekly-cleanup.service >/dev/null <<'EOF'
[Unit]
Description=Weekly conservative cleanup for hosting VPS
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/weekly-cleanup.sh
EOF
sudo tee /etc/systemd/system/weekly-cleanup.timer >/dev/null <<'EOF'
[Unit]
Description=Run weekly cleanup on schedule
[Timer]
OnCalendar=Sun *-*-* 03:05:00
Persistent=true
[Install]
WantedBy=timers.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now weekly-cleanup.timer
Step 7 — Add fast health checks (HTTP, SSL, disk, and failed services)
A maintenance routine needs a quick green/red signal.
This set of checks catches most “hosting VPS is acting weird” problems early.
One-command local health script
Create /usr/local/sbin/healthcheck.sh:
sudo tee /usr/local/sbin/healthcheck.sh >/dev/null <<'EOF'
#!/bin/sh
set -eu
HOST="${1:-localhost}"
URL="${2:-http://127.0.0.1/}"
echo "== Host =="
hostnamectl 2>/dev/null | sed -n '1,8p' || hostname
echo "\n== Uptime/load =="
uptime
echo "\n== Disk =="
df -hT | egrep -v 'tmpfs|devtmpfs' || true
echo "\n== Memory =="
free -h
echo "\n== Failed systemd units =="
systemctl --failed --no-pager || true
echo "\n== Listening ports (top) =="
ss -tulpen | head -n 30
echo "\n== HTTP check =="
curl -fsS -o /dev/null -w 'HTTP %{http_code} in %{time_total}s\n' "$URL" || echo "HTTP check failed"
echo "\n== Reboot required? =="
[ -f /var/run/reboot-required ] && echo "YES" || echo "no"
EOF
sudo chmod 0755 /usr/local/sbin/healthcheck.sh
Run it:
sudo /usr/local/sbin/healthcheck.sh localhost http://127.0.0.1/
Need deeper response-time troubleshooting? Use your existing guide: diagnose slow website response on Ubuntu.
SSL expiration check (practical, not fancy)
For a single domain on a VPS, this is usually enough. It helps you spot an expiring cert before it becomes a ticket.
DOMAIN="example.com"
echo | openssl s_client -servername "$DOMAIN" -connect "$DOMAIN:443" 2>/dev/null | \
openssl x509 -noout -dates -issuer -subject
If you manage certificates in WHM, keep your workflow consistent with: cPanel SSL certificate management.
Step 8 — Get notified: daily Logwatch report (or at least critical signals)
You don’t need a full monitoring stack to catch obvious problems.
A daily summary email often surfaces brute-force spikes, repeated auth failures, or a service that keeps flapping.
On Ubuntu/Debian, Logwatch is a good fit. If you haven’t set it up, follow: Logwatch daily security & service reports.
Minimal alternative: email yourself the maintenance change log once a week.
If your server can send mail locally, you can add this to a timer script:
# example snippet (requires mailutils or similar)
# tail -n 200 /var/log/maintenance/changes.log | mail -s "Weekly VPS maintenance log" you@example.com
If your VPS also sends mail to the outside world, do deliverability properly (SPF/DKIM/DMARC and reverse DNS).
Otherwise, alerts will vanish into spam at the exact wrong moment.
These guides help:
Step 9 — Maintenance checklist you can actually follow (weekly + monthly)
Automation handles repetition. A short human checklist catches the odd stuff.
Think unexpected growth, weird auth patterns, and “why is this slow now?” moments.
Weekly (10–15 minutes)
- Run:
sudo /usr/local/sbin/healthcheck.sh - Review:
sudo tail -n 120 /var/log/maintenance/changes.log - Confirm no disk hotspots:
sudo du -xhd1 /var | sort -h | tail - Check failed units:
systemctl --failed - Confirm backups completed (and the size looks sane)
Monthly (30–45 minutes)
- Restore-test one backup to a staging path or temporary VPS.
- Review SSH access and remove stale keys/users.
- Spot-check SSL expiration on key domains.
- Verify DNS TTLs and records match your intended architecture.
If your backups aren’t automated or you never test restores, make that the next task.
Use: VPS backup setup with snapshots, offsite copies, and restore tests.
Step 10 — Common maintenance failures (and quick fixes)
Unattended upgrades stopped running
- Check timers:
systemctl list-timers apt-daily-upgrade.timer - Check logs:
less /var/log/unattended-upgrades/unattended-upgrades.log - Look for dpkg locks:
ps aux | egrep 'apt|dpkg' | grep -v egrep
Disk keeps filling even with logrotate
- Find biggest directories:
sudo du -xhd1 /var | sort -h | tail - Find biggest files:
sudo find /var -xdev -type f -size +200M -printf '%s %p\n' | sort -n | tail - Check journald usage:
journalctl --disk-usage
Planned reboot caused a longer outage than expected
- Check what didn’t start:
systemctl --failed - Read the previous boot errors:
journalctl -b -1 -p err --no-pager | tail -n 200 - Confirm web stack order (reverse proxy, PHP-FPM, etc.)
Sites feel slower after updates
Don’t guess. Measure where time is going (web server, PHP, disk I/O).
If you host WordPress, these are usually the best places to start:
Summary: keep your hosting VPS boring (that’s the goal)
Good maintenance is quiet. Updates land on schedule. Reboots happen only when they’re required. Disk usage stays predictable.
You can also point to a log that shows what changed.
If your current routine is “I’ll check it later,” the timers and scripts above will buy you reliability quickly.
If you want a clean place to implement this workflow, start with a HostMyCode VPS so you control patching and maintenance windows.
If you’d rather hand off the routine upkeep while keeping your stack flexible, choose managed VPS hosting and keep your time for application work.
If you’re standardizing maintenance across multiple websites, a VPS gives you direct control over updates, reboot windows, and log retention. HostMyCode offers both HostMyCode VPS plans (full admin control) and managed VPS hosting if you want the routine work handled while you stay focused on the applications.
FAQ
Should I enable unattended upgrades on a production hosting server?
Yes for security updates, as long as you schedule them into a maintenance window and keep logs. Avoid automatic distribution upgrades and major version jumps.
How often should I reboot a VPS?
Reboot when needed (kernel/glibc updates) and on a predictable schedule if you prefer. The safest pattern is “reboot only when /var/run/reboot-required exists,” inside a window.
What log sizes are reasonable for journald on a VPS?
For small-to-mid hosting VPS nodes, capping the system journal to 512MB–2GB is typical. The right value depends on disk size and how quickly you need historical logs.
What’s the fastest way to spot why disk usage keeps growing?
Start with du -xhd1 /var to find the hot directory, then find /var -xdev -type f -size +200M to pinpoint large files. Check journalctl --disk-usage early.
Can I use this approach on a dedicated server too?
Yes. Dedicated servers benefit even more because they often run more sites and generate more logs. The same timers and policies apply; just tune limits to your storage size.