Automating Daily Server Chores with Cron-Style Orchestration
Automate daily server chores with cron and systemd timers that drive backups, patching, and cert renewal, plus a fleet-wide converge pass.
Netbay Cloud Team
Netbay Engineering
On this page
Day-two operations are mostly repetitive chores: nightly backups, weekly patching, cert renewal, log trimming, status checks. Each is trivial in isolation and collectively they eat weekends when done by hand. The trick is to make them scheduled, logged, and re-runnable, so a failure stays visible in a log file instead of being discovered months later. This post shows the classic cron route and the more modern systemd timer route, then the fleet-wide equivalent.
The Classic: Crontab
A cron line needs three pieces: a schedule, a command, and an output destination. The last one is what everyone forgets — without redirection, cron mails output to the local root mailbox and nobody reads it:
0 2 * * * /usr/local/bin/backup-db.sh >> /var/log/backup-db.log 2>&1
15 4 * * * certbot renew --quiet --deploy-hook "systemctl reload nginx" >> /var/log/cert-renew.log 2>&1
0 3 * * 6 ansible-playbook -i /srv/iac/hosts.ini /srv/iac/patch.yml >> /var/log/ansible-patch.log 2>&1The first field is the minute, then hour, day of month, month, and weekday. The third line is the interesting one: instead of a copy-paste shell script per machine, the job is an Ansible playbook stored in version control, so the chore itself is code. Every scheduled thing should point at a script or playbook that is idempotent, because a missed run on a crashed night will be re-run later whether you planned for it or not.
The Modern Route: systemd Timers
Systemd timers replace cron's old machinery with unit files, and they add two practical wins: Persistent=true runs a missed job after a reboot, and OnBootSec helps you stagger jobs across a fleet:
[Unit]
Description=Nightly database backup
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
RandomizedDelaySec=300
[Install]
WantedBy=timers.target# ship the service and timer units, then activate
sudo cp backup-db.{service,timer} /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now backup-db.timer
systemctl list-timersRandomizedDelaySec spreads the start within a window, which matters when fifty instances would otherwise hit the backup server at the same second. The timer fires the matching backup-db.service unit, so per-service logging and status reporting come from the usual systemctl mechanisms.
Chore Discipline That Scales
Three habits keep scheduled automation trustworthy as the fleet grows:
- **Every job writes a log you actually watch** — a spare disk that is quietly full is a backup that silently did not happen.
- **Converge, then schedule** — run the same playbook manually after a failed run; the playbook should repair, not append a second copy of a line.
- **Alert on absence, not just failure** — if the 2 AM job simply never fires, a missing log entry is your only clue, so a heartbeat check beats any wall of logs.
Takeaway
Automate the chores, log everything, and make each job its own small idempotent playbook rather than a growing root shell script. Start with one job — your nightly backup — and let the pattern spread until the weekend patch pass is the least exciting thing on your calendar. Netbay instances make ideal test subjects for this: provision a box, wire a timer, break it, and re-provision on netbayhosts.in without anyone noticing.
Keep reading
Follow along on a real VPS
Deploy Linux in under 60 seconds
These guides are written against Ubuntu, Debian, and RHEL-family images — the same ones on NetBay.
Deploy an instance